Version 1.20.0-dev.4.0

Merge commit '991afce3bc636aaf26c952b461941da455897042' into dev
diff --git a/.travis.yml b/.travis.yml
index 8ba30a6..369488c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -66,3 +66,8 @@
   allow_failures:
     - env: TEST=node
     - env: ANALYZER=master CXX=clang++
+notifications:
+  email:
+    recipients:
+      - dev-compiler+buildbot@dartlang.org
+    on_failure: change
diff --git a/DEPS b/DEPS
index 7c0d495..e53f378 100644
--- a/DEPS
+++ b/DEPS
@@ -71,7 +71,7 @@
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@2.0.2",
   "kernel_rev": "@9509d282a62fe025f8d6242bb233b02e0a7fee04",
-  "linter_tag": "@0.1.24",
+  "linter_tag": "@0.1.26",
   "logging_tag": "@0.11.3+1",
   "markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
   "matcher_tag": "@0.12.0+2",
@@ -79,7 +79,7 @@
   "mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
   "mustache4dart_tag" : "@v1.0.10",
   "oauth2_tag": "@1.0.2",
-  "observatory_pub_packages_rev": "@a01235b5b71df27b602dae4676d0bf771cbe7fa2",
+  "observatory_pub_packages_rev": "@26aad88f1c1915d39bbcbff3cad589e2402fdcf1",
   "observe_tag": "@0.13.5",
   "package_config_tag": "@1.0.0",
   "package_resolver_tag": "@1.0.2",
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index f7cc387..6637ad7 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -111,7 +111,7 @@
 </style></head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version 1.16.0</h1>
+    <h1 style="color:#999999">Version 1.17.0</h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -3263,6 +3263,11 @@
               alias”). This data is omitted if there is no referenced
               element.
             </p>
+          </dd><dt class="field"><b>isDeprecated (<span style="color:#999999">optional</span> bool)</b></dt><dd>
+            
+            <p>
+              True if the referenced element is deprecated.
+            </p>
           </dd><dt class="field"><b>parameter (<span style="color:#999999">optional</span> String)</b></dt><dd>
             
             <p>
@@ -3669,7 +3674,37 @@
           returned by the refactoring requests.
         </p>
         
-      <dl><dt class="value">INFO</dt><dt class="value">WARNING</dt><dt class="value">ERROR</dt><dt class="value">FATAL</dt></dl></dd><dt class="typeDefinition"><a name="type_RemoveContentOverlay">RemoveContentOverlay: object</a></dt><dd>
+      <dl><dt class="value">INFO</dt><dd>
+            
+            <p>A minor code problem. No example, because it is not used yet.
+            </p>
+          </dd><dt class="value">WARNING</dt><dd>
+            
+            <p>A minor code problem. For example names of local variables
+              should be camel case and start with a lower case letter. Staring
+              the name of a variable with an upper case is OK from the language
+              point of view, but it is nice to warn the user.
+            </p>
+          </dd><dt class="value">ERROR</dt><dd>
+            
+            <p>The refactoring technically can be performed, but there is a
+              logical problem. For example the name of a local variable being
+              extracted conflicts with another name in the scope, or
+              duplicate parameter names in the method being extracted, or
+              a conflict between a parameter name and a local variable, etc.
+              In some cases the location of the problem is also provided, so
+              the IDE can show user the location and the problem, and let the
+              user decide whether she wants to perform the refactoring. For
+              example the name conflict might be expected, and the user wants
+              to fix it afterwards.
+            </p>
+          </dd><dt class="value">FATAL</dt><dd>
+            
+            <p>A fatal error, which prevents performing the refactoring.
+              For example the name of a local variable being extracted is not a
+              valid identifier, or selection is not a valid expression.
+            </p>
+          </dd></dl></dd><dt class="typeDefinition"><a name="type_RemoveContentOverlay">RemoveContentOverlay: object</a></dt><dd>
         <p>
           A directive to remove an existing file content overlay.
           After processing this directive, the file contents will once
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index 4b8fe8b..ce67998 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -11298,6 +11298,7 @@
  *   "dartdoc": optional String
  *   "elementDescription": optional String
  *   "elementKind": optional String
+ *   "isDeprecated": optional bool
  *   "parameter": optional String
  *   "propagatedType": optional String
  *   "staticType": optional String
@@ -11322,6 +11323,8 @@
 
   String _elementKind;
 
+  bool _isDeprecated;
+
   String _parameter;
 
   String _propagatedType;
@@ -11455,6 +11458,18 @@
   }
 
   /**
+   * True if the referenced element is deprecated.
+   */
+  bool get isDeprecated => _isDeprecated;
+
+  /**
+   * True if the referenced element is deprecated.
+   */
+  void set isDeprecated(bool value) {
+    this._isDeprecated = value;
+  }
+
+  /**
    * A human-readable description of the parameter corresponding to the
    * expression being hovered over. This data is omitted if the location is not
    * in an argument to a function.
@@ -11500,7 +11515,7 @@
     this._staticType = value;
   }
 
-  HoverInformation(int offset, int length, {String containingLibraryPath, String containingLibraryName, String containingClassDescription, String dartdoc, String elementDescription, String elementKind, String parameter, String propagatedType, String staticType}) {
+  HoverInformation(int offset, int length, {String containingLibraryPath, String containingLibraryName, String containingClassDescription, String dartdoc, String elementDescription, String elementKind, bool isDeprecated, String parameter, String propagatedType, String staticType}) {
     this.offset = offset;
     this.length = length;
     this.containingLibraryPath = containingLibraryPath;
@@ -11509,6 +11524,7 @@
     this.dartdoc = dartdoc;
     this.elementDescription = elementDescription;
     this.elementKind = elementKind;
+    this.isDeprecated = isDeprecated;
     this.parameter = parameter;
     this.propagatedType = propagatedType;
     this.staticType = staticType;
@@ -11555,6 +11571,10 @@
       if (json.containsKey("elementKind")) {
         elementKind = jsonDecoder.decodeString(jsonPath + ".elementKind", json["elementKind"]);
       }
+      bool isDeprecated;
+      if (json.containsKey("isDeprecated")) {
+        isDeprecated = jsonDecoder.decodeBool(jsonPath + ".isDeprecated", json["isDeprecated"]);
+      }
       String parameter;
       if (json.containsKey("parameter")) {
         parameter = jsonDecoder.decodeString(jsonPath + ".parameter", json["parameter"]);
@@ -11567,7 +11587,7 @@
       if (json.containsKey("staticType")) {
         staticType = jsonDecoder.decodeString(jsonPath + ".staticType", json["staticType"]);
       }
-      return new HoverInformation(offset, length, containingLibraryPath: containingLibraryPath, containingLibraryName: containingLibraryName, containingClassDescription: containingClassDescription, dartdoc: dartdoc, elementDescription: elementDescription, elementKind: elementKind, parameter: parameter, propagatedType: propagatedType, staticType: staticType);
+      return new HoverInformation(offset, length, containingLibraryPath: containingLibraryPath, containingLibraryName: containingLibraryName, containingClassDescription: containingClassDescription, dartdoc: dartdoc, elementDescription: elementDescription, elementKind: elementKind, isDeprecated: isDeprecated, parameter: parameter, propagatedType: propagatedType, staticType: staticType);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "HoverInformation", json);
     }
@@ -11595,6 +11615,9 @@
     if (elementKind != null) {
       result["elementKind"] = elementKind;
     }
+    if (isDeprecated != null) {
+      result["isDeprecated"] = isDeprecated;
+    }
     if (parameter != null) {
       result["parameter"] = parameter;
     }
@@ -11621,6 +11644,7 @@
           dartdoc == other.dartdoc &&
           elementDescription == other.elementDescription &&
           elementKind == other.elementKind &&
+          isDeprecated == other.isDeprecated &&
           parameter == other.parameter &&
           propagatedType == other.propagatedType &&
           staticType == other.staticType;
@@ -11639,6 +11663,7 @@
     hash = JenkinsSmiHash.combine(hash, dartdoc.hashCode);
     hash = JenkinsSmiHash.combine(hash, elementDescription.hashCode);
     hash = JenkinsSmiHash.combine(hash, elementKind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, isDeprecated.hashCode);
     hash = JenkinsSmiHash.combine(hash, parameter.hashCode);
     hash = JenkinsSmiHash.combine(hash, propagatedType.hashCode);
     hash = JenkinsSmiHash.combine(hash, staticType.hashCode);
@@ -13895,12 +13920,37 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class RefactoringProblemSeverity implements Enum {
+  /**
+   * A minor code problem. No example, because it is not used yet.
+   */
   static const INFO = const RefactoringProblemSeverity._("INFO");
 
+  /**
+   * A minor code problem. For example names of local variables should be camel
+   * case and start with a lower case letter. Staring the name of a variable
+   * with an upper case is OK from the language point of view, but it is nice
+   * to warn the user.
+   */
   static const WARNING = const RefactoringProblemSeverity._("WARNING");
 
+  /**
+   * The refactoring technically can be performed, but there is a logical
+   * problem. For example the name of a local variable being extracted
+   * conflicts with another name in the scope, or duplicate parameter names in
+   * the method being extracted, or a conflict between a parameter name and a
+   * local variable, etc. In some cases the location of the problem is also
+   * provided, so the IDE can show user the location and the problem, and let
+   * the user decide whether she wants to perform the refactoring. For example
+   * the name conflict might be expected, and the user wants to fix it
+   * afterwards.
+   */
   static const ERROR = const RefactoringProblemSeverity._("ERROR");
 
+  /**
+   * A fatal error, which prevents performing the refactoring. For example the
+   * name of a local variable being extracted is not a valid identifier, or
+   * selection is not a valid expression.
+   */
   static const FATAL = const RefactoringProblemSeverity._("FATAL");
 
   /**
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 25d425c..c8a653a 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -81,7 +81,7 @@
    * The version of the analysis server. The value should be replaced
    * automatically during the build.
    */
-  static final String VERSION = '1.15.0';
+  static final String VERSION = '1.17.0';
 
   /**
    * The number of milliseconds to perform operations before inserting
@@ -1631,10 +1631,8 @@
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
     AnalysisContext context = analysisServer.folderMap[contextFolder];
     if (context != null) {
-      ApplyChangesStatus changesStatus = context.applyChanges(changeSet);
-      if (changesStatus.hasChanges) {
-        analysisServer.schedulePerformAnalysisOperation(context);
-      }
+      context.applyChanges(changeSet);
+      analysisServer.schedulePerformAnalysisOperation(context);
       List<String> flushedFiles = new List<String>();
       for (Source source in changeSet.removedSources) {
         flushedFiles.add(source.fullName);
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index d4e10b4..1e3b807 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -56,6 +56,7 @@
         // description
         hover.elementDescription = element.toString();
         hover.elementKind = element.kind.displayName;
+        hover.isDeprecated = element.isDeprecated;
         // not local element
         if (element.enclosingElement is! ExecutableElement) {
           // containing class
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index d0b0636..c69d806 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -15,6 +15,7 @@
     show LocalDeclarationVisitor;
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analysis_server/src/utilities/documentation.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -236,7 +237,10 @@
   void declaredClass(ClassDeclaration declaration) {
     if (optype.includeTypeNameSuggestions) {
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.name, NO_RETURN_TYPE, protocol.ElementKind.CLASS,
+          declaration.documentationComment,
+          declaration.name,
+          NO_RETURN_TYPE,
+          protocol.ElementKind.CLASS,
           isAbstract: declaration.isAbstract,
           isDeprecated: _isDeprecated(declaration));
     }
@@ -245,9 +249,13 @@
   @override
   void declaredClassTypeAlias(ClassTypeAlias declaration) {
     if (optype.includeTypeNameSuggestions) {
-      _addLocalSuggestion_includeTypeNameSuggestions(declaration.name,
-          NO_RETURN_TYPE, protocol.ElementKind.CLASS_TYPE_ALIAS,
-          isAbstract: true, isDeprecated: _isDeprecated(declaration));
+      _addLocalSuggestion_includeTypeNameSuggestions(
+          declaration.documentationComment,
+          declaration.name,
+          NO_RETURN_TYPE,
+          protocol.ElementKind.CLASS_TYPE_ALIAS,
+          isAbstract: true,
+          isDeprecated: _isDeprecated(declaration));
     }
   }
 
@@ -255,7 +263,10 @@
   void declaredEnum(EnumDeclaration declaration) {
     if (optype.includeTypeNameSuggestions) {
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.name, NO_RETURN_TYPE, protocol.ElementKind.ENUM,
+          declaration.documentationComment,
+          declaration.name,
+          NO_RETURN_TYPE,
+          protocol.ElementKind.ENUM,
           isDeprecated: _isDeprecated(declaration));
       for (EnumConstantDeclaration enumConstant in declaration.constants) {
         if (!enumConstant.isSynthetic) {
@@ -274,7 +285,10 @@
       bool deprecated = _isDeprecated(fieldDecl) || _isDeprecated(varDecl);
       TypeName typeName = fieldDecl.fields.type;
       _addLocalSuggestion_includeReturnValueSuggestions(
-          varDecl.name, typeName, protocol.ElementKind.FIELD,
+          fieldDecl.documentationComment,
+          varDecl.name,
+          typeName,
+          protocol.ElementKind.FIELD,
           isDeprecated: deprecated,
           relevance: DART_RELEVANCE_LOCAL_FIELD,
           classDecl: fieldDecl.parent);
@@ -306,7 +320,10 @@
         relevance = DART_RELEVANCE_LOCAL_FUNCTION;
       }
       _addLocalSuggestion_includeReturnValueSuggestions(
-          declaration.name, typeName, elemKind,
+          declaration.documentationComment,
+          declaration.name,
+          typeName,
+          elemKind,
           isDeprecated: _isDeprecated(declaration),
           param: declaration.functionExpression.parameters,
           relevance: relevance);
@@ -317,9 +334,13 @@
   void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {
     if (optype.includeTypeNameSuggestions) {
       // TODO (danrubel) determine parameters and return type
-      _addLocalSuggestion_includeTypeNameSuggestions(declaration.name,
-          declaration.returnType, protocol.ElementKind.FUNCTION_TYPE_ALIAS,
-          isAbstract: true, isDeprecated: _isDeprecated(declaration));
+      _addLocalSuggestion_includeTypeNameSuggestions(
+          declaration.documentationComment,
+          declaration.name,
+          declaration.returnType,
+          protocol.ElementKind.FUNCTION_TYPE_ALIAS,
+          isAbstract: true,
+          isDeprecated: _isDeprecated(declaration));
     }
   }
 
@@ -332,7 +353,7 @@
   void declaredLocalVar(SimpleIdentifier id, TypeName typeName) {
     if (optype.includeReturnValueSuggestions) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          id, typeName, protocol.ElementKind.LOCAL_VARIABLE,
+          null, id, typeName, protocol.ElementKind.LOCAL_VARIABLE,
           relevance: DART_RELEVANCE_LOCAL_VARIABLE);
     }
   }
@@ -366,7 +387,10 @@
         relevance = DART_RELEVANCE_LOCAL_METHOD;
       }
       _addLocalSuggestion_includeReturnValueSuggestions(
-          declaration.name, typeName, elemKind,
+          declaration.documentationComment,
+          declaration.name,
+          typeName,
+          elemKind,
           isAbstract: declaration.isAbstract,
           isDeprecated: _isDeprecated(declaration),
           classDecl: declaration.parent,
@@ -379,7 +403,7 @@
   void declaredParam(SimpleIdentifier id, TypeName typeName) {
     if (optype.includeReturnValueSuggestions) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          id, typeName, protocol.ElementKind.PARAMETER,
+          null, id, typeName, protocol.ElementKind.PARAMETER,
           relevance: DART_RELEVANCE_PARAMETER);
     }
   }
@@ -389,14 +413,17 @@
       VariableDeclarationList varList, VariableDeclaration varDecl) {
     if (optype.includeReturnValueSuggestions) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          varDecl.name, varList.type, protocol.ElementKind.TOP_LEVEL_VARIABLE,
+          varDecl.documentationComment,
+          varDecl.name,
+          varList.type,
+          protocol.ElementKind.TOP_LEVEL_VARIABLE,
           isDeprecated: _isDeprecated(varList) || _isDeprecated(varDecl),
           relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
     }
   }
 
-  void _addLocalSuggestion(
-      SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
+  void _addLocalSuggestion(Comment documentationComment, SimpleIdentifier id,
+      TypeName typeName, protocol.ElementKind elemKind,
       {bool isAbstract: false,
       bool isDeprecated: false,
       ClassDeclaration classDecl,
@@ -409,6 +436,7 @@
         id, kind, isDeprecated, relevance, typeName,
         classDecl: classDecl);
     if (suggestion != null) {
+      _setDocumentation(suggestion, documentationComment);
       if (privateMemberRelevance != null &&
           suggestion.completion.startsWith('_')) {
         suggestion.relevance = privateMemberRelevance;
@@ -464,7 +492,10 @@
   }
 
   void _addLocalSuggestion_includeReturnValueSuggestions(
-      SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
+      Comment documentationComment,
+      SimpleIdentifier id,
+      TypeName typeName,
+      protocol.ElementKind elemKind,
       {bool isAbstract: false,
       bool isDeprecated: false,
       ClassDeclaration classDecl,
@@ -473,7 +504,7 @@
     relevance = optype.returnValueSuggestionsFilter(
         _staticTypeOfIdentifier(id), relevance);
     if (relevance != null) {
-      _addLocalSuggestion(id, typeName, elemKind,
+      _addLocalSuggestion(documentationComment, id, typeName, elemKind,
           isAbstract: isAbstract,
           isDeprecated: isDeprecated,
           classDecl: classDecl,
@@ -499,7 +530,10 @@
   }
 
   void _addLocalSuggestion_includeTypeNameSuggestions(
-      SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
+      Comment documentationComment,
+      SimpleIdentifier id,
+      TypeName typeName,
+      protocol.ElementKind elemKind,
       {bool isAbstract: false,
       bool isDeprecated: false,
       ClassDeclaration classDecl,
@@ -508,7 +542,7 @@
     relevance = optype.typeNameSuggestionsFilter(
         _staticTypeOfIdentifier(id), relevance);
     if (relevance != null) {
-      _addLocalSuggestion(id, typeName, elemKind,
+      _addLocalSuggestion(documentationComment, id, typeName, elemKind,
           isAbstract: isAbstract,
           isDeprecated: isDeprecated,
           classDecl: classDecl,
@@ -571,4 +605,21 @@
       return id.staticType;
     }
   }
+
+  /**
+   * If the given [documentationComment] is not `null`, fill the [suggestion]
+   * documentation fields.
+   */
+  static void _setDocumentation(
+      CompletionSuggestion suggestion, Comment documentationComment) {
+    if (documentationComment != null) {
+      String text = documentationComment.tokens
+          .map((Token t) => t.toString())
+          .join('\n')
+          .replaceAll('\r\n', '\n');
+      String doc = removeDartDocDelimiters(text);
+      suggestion.docComplete = doc;
+      suggestion.docSummary = getDartDocSummary(doc);
+    }
+  }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 1ae3201..42ccd71 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -1178,7 +1178,7 @@
       return;
     }
     // prepare change
-    String showCombinator = ' show ${StringUtils.join(referencedNames, ', ')}';
+    String showCombinator = ' show ${referencedNames.join(', ')}';
     _addInsertEdit(importDirective.end - 1, showCombinator);
     // add proposal
     _addAssist(DartAssistKind.IMPORT_ADD_SHOW, []);
@@ -1711,7 +1711,7 @@
         String elseTarget = _getNodeText(elseAssignment.leftHandSide);
         if (thenAssignment.operator.type == TokenType.EQ &&
             elseAssignment.operator.type == TokenType.EQ &&
-            StringUtils.equals(thenTarget, elseTarget)) {
+            thenTarget == elseTarget) {
           String conditionSrc = _getNodeText(ifStatement.condition);
           String theSrc = _getNodeText(thenAssignment.rightHandSide);
           String elseSrc = _getNodeText(elseAssignment.rightHandSide);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 12b27fa..dff8dff 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -863,7 +863,7 @@
       }
       // add super constructor name
       sb.append('super');
-      if (!StringUtils.isEmpty(constructorName)) {
+      if (!isEmpty(constructorName)) {
         sb.append('.');
         sb.append(constructorName);
       }
@@ -1480,7 +1480,7 @@
         // don't add this library again
         alreadyImportedWithPrefix.add(libraryElement.source);
         // update library
-        String newShowCode = 'show ${StringUtils.join(showNames, ", ")}';
+        String newShowCode = 'show ${showNames.join(', ')}';
         _addReplaceEdit(
             rf.rangeOffsetEnd(showCombinator), newShowCode, unitLibraryElement);
         _addFix(DartFixKind.IMPORT_LIBRARY_SHOW, [libraryName]);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 32fdf6b..4c613cfd 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -49,7 +49,7 @@
  */
 String _getNormalizedSource(String src) {
   List<Token> selectionTokens = TokenUtils.getTokens(src);
-  return StringUtils.join(selectionTokens, _TOKEN_SEPARATOR);
+  return selectionTokens.join(_TOKEN_SEPARATOR);
 }
 
 /**
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index 9d5436b..bbf8cbf 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -238,6 +238,24 @@
     expect(hover.parameter, isNull);
   }
 
+  test_expression_method_deprecated() async {
+    addTestFile('''
+class A {
+  @deprecated
+  static void test() {}
+}
+main() {
+  A.test();
+}
+''');
+    HoverInformation hover = await prepareHover('test();');
+    // element
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.elementDescription, 'test() → void');
+    expect(hover.elementKind, 'method');
+    expect(hover.isDeprecated, isTrue);
+  }
+
   test_expression_method_invocation() async {
     addTestFile('''
 library my.library;
@@ -258,6 +276,7 @@
     expect(hover.containingLibraryPath, testFile);
     expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
     expect(hover.elementKind, 'method');
+    expect(hover.isDeprecated, isFalse);
     // types
     expect(hover.staticType, '(int, String) → List<String>');
     expect(hover.propagatedType, isNull);
@@ -409,6 +428,7 @@
       // no parameter
       expect(hover.parameter, isNull);
     }
+
     {
       HoverInformation hover = await prepareHover('new A');
       onConstructor(hover);
@@ -445,6 +465,7 @@
       expect(hover.elementDescription, 'A.named() → A');
       expect(hover.elementKind, 'constructor');
     }
+
     {
       HoverInformation hover = await prepareHover('new A');
       onConstructor(hover);
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index af36f04..5b4efed 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -529,28 +529,6 @@
     });
   }
 
-  test_watch_modifyFile_hasOverlay() async {
-    server.serverServices.add(ServerService.STATUS);
-    // configure the project
-    String projectPath = '/root';
-    String filePath = '/root/test.dart';
-    resourceProvider.newFolder(projectPath);
-    resourceProvider.newFile(filePath, '// 111');
-    server.setAnalysisRoots('0', ['/root'], [], {});
-    await pumpEventQueue();
-    // add overlay
-    server.updateContent('1', {filePath: new AddContentOverlay('// 222')});
-    await pumpEventQueue();
-    // update the file
-    channel.notificationsReceived.clear();
-    resourceProvider.modifyFile(filePath, '// 333');
-    await pumpEventQueue();
-    // the file has an overlay, so the file-system change was ignored
-    expect(channel.notificationsReceived.any((notification) {
-      return notification.event == SERVER_STATUS;
-    }), isFalse);
-  }
-
   void _assertContextOfFolder(
       AnalysisContext context, String expectedFolderPath) {
     Folder expectedFolder = resourceProvider.newFolder(expectedFolderPath);
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
index c2fb7a1..1ef8e4c 100644
--- a/pkg/analysis_server/test/completion_test_support.dart
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -151,18 +151,18 @@
           modifiedSource.substring(index + n);
     }
     if (modifiedSource == originalSource) {
-      throw new IllegalStateException("No tests in source: " + originalSource);
+      throw new StateError("No tests in source: " + originalSource);
     }
     for (String result in validationStrings) {
       if (result.length < 3) {
-        throw new IllegalStateException("Invalid location result: " + result);
+        throw new StateError("Invalid location result: " + result);
       }
       String id = result.substring(0, 1);
       String sign = result.substring(1, 2);
       String value = result.substring(2);
       LocationSpec test = tests[id];
       if (test == null) {
-        throw new IllegalStateException(
+        throw new StateError(
             "Invalid location result id: $id for: $result");
       }
       test.source = modifiedSource;
@@ -172,7 +172,7 @@
         test.negativeResults.add(value);
       } else {
         String err = "Invalid location result sign: $sign for: $result";
-        throw new IllegalStateException(err);
+        throw new StateError(err);
       }
     }
     List<String> badPoints = <String>[];
@@ -200,7 +200,7 @@
           err..write(' ')..write(ch);
         }
       }
-      throw new IllegalStateException(err.toString());
+      throw new StateError(err.toString());
     }
     return tests.values.toList();
   }
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 1443aa0..5c8e84a 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -1701,6 +1701,7 @@
  *   "dartdoc": optional String
  *   "elementDescription": optional String
  *   "elementKind": optional String
+ *   "isDeprecated": optional bool
  *   "parameter": optional String
  *   "propagatedType": optional String
  *   "staticType": optional String
@@ -1717,6 +1718,7 @@
     "dartdoc": isString,
     "elementDescription": isString,
     "elementKind": isString,
+    "isDeprecated": isBool,
     "parameter": isString,
     "propagatedType": isString,
     "staticType": isString
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index 8cbed55..004e262 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -1923,6 +1923,110 @@
     assertNotSuggested('bar');
   }
 
+  test_doc_classMember() async {
+    String docLines = r'''
+  /// My documentation.
+  /// Short description.
+  ///
+  /// Longer description.
+''';
+    void assertDoc(CompletionSuggestion suggestion) {
+      expect(suggestion.docSummary, 'My documentation.\nShort description.');
+      expect(suggestion.docComplete,
+          'My documentation.\nShort description.\n\nLonger description.');
+    }
+
+    addTestSource('''
+class C {
+$docLines
+  int myField;
+
+$docLines
+  myMethod() {}
+
+$docLines
+  int get myGetter => 0;
+
+  main() {^}
+}''');
+    await computeSuggestions();
+    {
+      CompletionSuggestion suggestion = assertSuggestField('myField', 'int',
+          relevance: DART_RELEVANCE_LOCAL_FIELD);
+      assertDoc(suggestion);
+    }
+    {
+      CompletionSuggestion suggestion = assertSuggestMethod(
+          'myMethod', 'C', null,
+          relevance: DART_RELEVANCE_LOCAL_METHOD);
+      assertDoc(suggestion);
+    }
+    {
+      CompletionSuggestion suggestion = assertSuggestGetter('myGetter', 'int',
+          relevance: DART_RELEVANCE_LOCAL_ACCESSOR);
+      assertDoc(suggestion);
+    }
+  }
+
+  test_doc_topLevel() async {
+    String docLines = r'''
+/// My documentation.
+/// Short description.
+///
+/// Longer description.
+''';
+    void assertDoc(CompletionSuggestion suggestion) {
+      expect(suggestion.docSummary, 'My documentation.\nShort description.');
+      expect(suggestion.docComplete,
+          'My documentation.\nShort description.\n\nLonger description.');
+    }
+
+    addTestSource('''
+$docLines
+class MyClass {}
+
+$docLines
+class MyClassTypeAlias = Object with MyClass;
+
+$docLines
+enum MyEnum {A, B, C}
+
+$docLines
+void myFunction() {}
+
+$docLines
+int myVariable;
+
+main() {^}
+''');
+    await computeSuggestions();
+    {
+      CompletionSuggestion suggestion = assertSuggestClass('MyClass');
+      assertDoc(suggestion);
+    }
+    {
+      CompletionSuggestion suggestion =
+          assertSuggestClassTypeAlias('MyClassTypeAlias');
+      assertDoc(suggestion);
+    }
+    {
+      CompletionSuggestion suggestion = assertSuggestEnum('MyEnum');
+      assertDoc(suggestion);
+    }
+    {
+      CompletionSuggestion suggestion = assertSuggestFunction(
+          'myFunction', 'void',
+          relevance: DART_RELEVANCE_LOCAL_FUNCTION);
+      assertDoc(suggestion);
+    }
+    {
+      CompletionSuggestion suggestion = assertSuggestTopLevelVar(
+          'myVariable', 'int',
+          relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
+      assertDoc(suggestion);
+    }
+  }
+
   test_enum() async {
     addTestSource('enum E { one, two } main() {^}');
     await computeSuggestions();
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/HoverInformation.java b/pkg/analysis_server/tool/spec/generated/java/types/HoverInformation.java
index 79d233e..d1dd58d 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/HoverInformation.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/HoverInformation.java
@@ -95,6 +95,11 @@
   private final String elementKind;
 
   /**
+   * True if the referenced element is deprecated.
+   */
+  private final Boolean isDeprecated;
+
+  /**
    * A human-readable description of the parameter corresponding to the expression being hovered
    * over. This data is omitted if the location is not in an argument to a function.
    */
@@ -115,7 +120,7 @@
   /**
    * Constructor for {@link HoverInformation}.
    */
-  public HoverInformation(int offset, int length, String containingLibraryPath, String containingLibraryName, String containingClassDescription, String dartdoc, String elementDescription, String elementKind, String parameter, String propagatedType, String staticType) {
+  public HoverInformation(int offset, int length, String containingLibraryPath, String containingLibraryName, String containingClassDescription, String dartdoc, String elementDescription, String elementKind, Boolean isDeprecated, String parameter, String propagatedType, String staticType) {
     this.offset = offset;
     this.length = length;
     this.containingLibraryPath = containingLibraryPath;
@@ -124,6 +129,7 @@
     this.dartdoc = dartdoc;
     this.elementDescription = elementDescription;
     this.elementKind = elementKind;
+    this.isDeprecated = isDeprecated;
     this.parameter = parameter;
     this.propagatedType = propagatedType;
     this.staticType = staticType;
@@ -142,6 +148,7 @@
         ObjectUtilities.equals(other.dartdoc, dartdoc) &&
         ObjectUtilities.equals(other.elementDescription, elementDescription) &&
         ObjectUtilities.equals(other.elementKind, elementKind) &&
+        ObjectUtilities.equals(other.isDeprecated, isDeprecated) &&
         ObjectUtilities.equals(other.parameter, parameter) &&
         ObjectUtilities.equals(other.propagatedType, propagatedType) &&
         ObjectUtilities.equals(other.staticType, staticType);
@@ -158,10 +165,11 @@
     String dartdoc = jsonObject.get("dartdoc") == null ? null : jsonObject.get("dartdoc").getAsString();
     String elementDescription = jsonObject.get("elementDescription") == null ? null : jsonObject.get("elementDescription").getAsString();
     String elementKind = jsonObject.get("elementKind") == null ? null : jsonObject.get("elementKind").getAsString();
+    Boolean isDeprecated = jsonObject.get("isDeprecated") == null ? null : jsonObject.get("isDeprecated").getAsBoolean();
     String parameter = jsonObject.get("parameter") == null ? null : jsonObject.get("parameter").getAsString();
     String propagatedType = jsonObject.get("propagatedType") == null ? null : jsonObject.get("propagatedType").getAsString();
     String staticType = jsonObject.get("staticType") == null ? null : jsonObject.get("staticType").getAsString();
-    return new HoverInformation(offset, length, containingLibraryPath, containingLibraryName, containingClassDescription, dartdoc, elementDescription, elementKind, parameter, propagatedType, staticType);
+    return new HoverInformation(offset, length, containingLibraryPath, containingLibraryName, containingClassDescription, dartdoc, elementDescription, elementKind, isDeprecated, parameter, propagatedType, staticType);
   }
 
   public static List<HoverInformation> fromJsonArray(JsonArray jsonArray) {
@@ -228,6 +236,13 @@
   }
 
   /**
+   * True if the referenced element is deprecated.
+   */
+  public Boolean getIsDeprecated() {
+    return isDeprecated;
+  }
+
+  /**
    * The length of the range of characters that encompasses the cursor position and has the same
    * hover information as the cursor position.
    */
@@ -278,6 +293,7 @@
     builder.append(dartdoc);
     builder.append(elementDescription);
     builder.append(elementKind);
+    builder.append(isDeprecated);
     builder.append(parameter);
     builder.append(propagatedType);
     builder.append(staticType);
@@ -306,6 +322,9 @@
     if (elementKind != null) {
       jsonObject.addProperty("elementKind", elementKind);
     }
+    if (isDeprecated != null) {
+      jsonObject.addProperty("isDeprecated", isDeprecated);
+    }
     if (parameter != null) {
       jsonObject.addProperty("parameter", parameter);
     }
@@ -338,6 +357,8 @@
     builder.append(elementDescription + ", ");
     builder.append("elementKind=");
     builder.append(elementKind + ", ");
+    builder.append("isDeprecated=");
+    builder.append(isDeprecated + ", ");
     builder.append("parameter=");
     builder.append(parameter + ", ");
     builder.append("propagatedType=");
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RefactoringProblemSeverity.java b/pkg/analysis_server/tool/spec/generated/java/types/RefactoringProblemSeverity.java
index 35c8296..a8bfbdf 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RefactoringProblemSeverity.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RefactoringProblemSeverity.java
@@ -23,12 +23,33 @@
  */
 public class RefactoringProblemSeverity {
 
+  /**
+   * A minor code problem. No example, because it is not used yet.
+   */
   public static final String INFO = "INFO";
 
+  /**
+   * A minor code problem. For example names of local variables should be camel case and start with a
+   * lower case letter. Staring the name of a variable with an upper case is OK from the language
+   * point of view, but it is nice to warn the user.
+   */
   public static final String WARNING = "WARNING";
 
+  /**
+   * The refactoring technically can be performed, but there is a logical problem. For example the
+   * name of a local variable being extracted conflicts with another name in the scope, or duplicate
+   * parameter names in the method being extracted, or a conflict between a parameter name and a
+   * local variable, etc. In some cases the location of the problem is also provided, so the IDE can
+   * show user the location and the problem, and let the user decide whether she wants to perform the
+   * refactoring. For example the name conflict might be expected, and the user wants to fix it
+   * afterwards.
+   */
   public static final String ERROR = "ERROR";
 
+  /**
+   * A fatal error, which prevents performing the refactoring. For example the name of a local
+   * variable being extracted is not a valid identifier, or selection is not a valid expression.
+   */
   public static final String FATAL = "FATAL";
 
 }
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 6f4a788..cadad70 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -6,7 +6,7 @@
   </head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version <version>1.16.0</version></h1>
+    <h1 style="color:#999999">Version <version>1.17.0</version></h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -3093,6 +3093,12 @@
               element.
             </p>
           </field>
+          <field name="isDeprecated" optional="true">
+            <ref>bool</ref>
+            <p>
+              True if the referenced element is deprecated.
+            </p>
+          </field>
           <field name="parameter" optional="true">
             <ref>String</ref>
             <p>
@@ -3607,10 +3613,40 @@
           returned by the refactoring requests.
         </p>
         <enum>
-          <value><code>INFO</code></value>
-          <value><code>WARNING</code></value>
-          <value><code>ERROR</code></value>
-          <value><code>FATAL</code></value>
+          <value>
+            <code>INFO</code>
+            <p>A minor code problem. No example, because it is not used yet.
+            </p>
+          </value>
+          <value>
+            <code>WARNING</code>
+            <p>A minor code problem. For example names of local variables
+              should be camel case and start with a lower case letter. Staring
+              the name of a variable with an upper case is OK from the language
+              point of view, but it is nice to warn the user.
+            </p>
+          </value>
+          <value>
+            <code>ERROR</code>
+            <p>The refactoring technically can be performed, but there is a
+              logical problem. For example the name of a local variable being
+              extracted conflicts with another name in the scope, or
+              duplicate parameter names in the method being extracted, or
+              a conflict between a parameter name and a local variable, etc.
+              In some cases the location of the problem is also provided, so
+              the IDE can show user the location and the problem, and let the
+              user decide whether she wants to perform the refactoring. For
+              example the name conflict might be expected, and the user wants
+              to fix it afterwards.
+            </p>
+          </value>
+          <value>
+            <code>FATAL</code>
+            <p>A fatal error, which prevents performing the refactoring.
+              For example the name of a local variable being extracted is not a
+              valid identifier, or selection is not a valid expression.
+            </p>
+          </value>
         </enum>
       </type>
       <type name="RemoveContentOverlay">
diff --git a/pkg/analyzer/benchmark/errors_in_all_libraries.dart b/pkg/analyzer/benchmark/errors_in_all_libraries.dart
index be42c2b..ad004bf 100644
--- a/pkg/analyzer/benchmark/errors_in_all_libraries.dart
+++ b/pkg/analyzer/benchmark/errors_in_all_libraries.dart
@@ -12,10 +12,10 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
-import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/source/source_resource.dart';
@@ -32,20 +32,25 @@
     var start = new DateTime.now();
     AnalysisEngine.instance.clearCaches();
 
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.strongMode = true;
+    options.strongModeHints = true;
+
     PhysicalResourceProvider resourceProvider =
         PhysicalResourceProvider.INSTANCE;
-    DartSdk sdk = new FolderBasedDartSdk(
+    FolderBasedDartSdk sdk = new FolderBasedDartSdk(
         resourceProvider, resourceProvider.getFolder(args[0]));
+    sdk.analysisOptions = options;
+
+    ContextBuilder builder = new ContextBuilder(resourceProvider, null, null);
     AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
     context.sourceFactory = new SourceFactory([
       new DartUriResolver(sdk),
       new ResourceUriResolver(resourceProvider),
-      new PackageUriResolver([new JavaFile(packageRoot)])
+      new PackageMapUriResolver(resourceProvider,
+          builder.convertPackagesToMap(builder.createPackageMap(packageRoot)))
     ]);
-
-    AnalysisOptionsImpl options = context.analysisOptions;
-    options.strongMode = true;
-    options.strongModeHints = true;
+    context.analysisOptions = options;
 
     var mainSource =
         new FileSource(resourceProvider.getFile(p.fromUri(Platform.script)));
diff --git a/pkg/analyzer/example/resolver_driver.dart b/pkg/analyzer/example/resolver_driver.dart
index 73c5733..cf68857 100755
--- a/pkg/analyzer/example/resolver_driver.dart
+++ b/pkg/analyzer/example/resolver_driver.dart
@@ -10,9 +10,10 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart' hide File;
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
@@ -41,8 +42,9 @@
   ];
 
   if (packageRoot != null) {
-    var packageDirectory = new JavaFile(packageRoot);
-    resolvers.add(new PackageUriResolver([packageDirectory]));
+    ContextBuilder builder = new ContextBuilder(resourceProvider, null, null);
+    resolvers.add(new PackageMapUriResolver(resourceProvider,
+        builder.convertPackagesToMap(builder.createPackageMap(packageRoot))));
   }
 
   AnalysisContext context = AnalysisEngine.instance.createAnalysisContext()
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index 38fc38a..ad430c0 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -152,6 +152,7 @@
 
   @override
   List<int> readAsBytesSync() {
+    _throwIfWindowsDeviceDriver();
     try {
       return _file.readAsBytesSync();
     } on io.FileSystemException catch (exception) {
@@ -161,6 +162,7 @@
 
   @override
   String readAsStringSync() {
+    _throwIfWindowsDeviceDriver();
     try {
       return FileBasedSource.fileReadMode(_file.readAsStringSync());
     } on io.FileSystemException catch (exception) {
@@ -351,6 +353,33 @@
 
   @override
   String toString() => path;
+
+  /**
+   * If the operating system is Windows and the resource references one of the
+   * device drivers, throw a [FileSystemException].
+   *
+   * https://support.microsoft.com/en-us/kb/74496
+   */
+  void _throwIfWindowsDeviceDriver() {
+    if (io.Platform.isWindows) {
+      String shortName = this.shortName.toUpperCase();
+      if (shortName == r'CON' ||
+          shortName == r'PRN' ||
+          shortName == r'AUX' ||
+          shortName == r'CLOCK$' ||
+          shortName == r'NUL' ||
+          shortName == r'COM1' ||
+          shortName == r'LPT1' ||
+          shortName == r'LPT2' ||
+          shortName == r'LPT3' ||
+          shortName == r'COM2' ||
+          shortName == r'COM3' ||
+          shortName == r'COM4') {
+        throw new FileSystemException(
+            path, 'Windows device drivers cannot be read.');
+      }
+    }
+  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 29308ae..3dfa30c 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -473,7 +473,7 @@
     if (identical(_sourceFactory, factory)) {
       return;
     } else if (factory.context != null) {
-      throw new IllegalStateException(
+      throw new StateError(
           "Source factories cannot be shared between contexts");
     }
     if (_sourceFactory != null) {
@@ -620,9 +620,9 @@
   }
 
   @override
-  ApplyChangesStatus applyChanges(ChangeSet changeSet) {
+  void applyChanges(ChangeSet changeSet) {
     if (changeSet.isEmpty) {
-      return new ApplyChangesStatus(false);
+      return;
     }
     //
     // First, compute the list of sources that have been removed.
@@ -665,11 +665,6 @@
           changeSet.addedSources, changedSources, removedSources);
     }
     _onSourcesChangedController.add(new SourcesChangedEvent(changeSet));
-    return new ApplyChangesStatus(changeSet.addedSources.isNotEmpty ||
-        changeSet.changedContents.isNotEmpty ||
-        changeSet.deletedSources.isNotEmpty ||
-        changedSources.isNotEmpty ||
-        removedSources.isNotEmpty);
   }
 
   @override
@@ -2312,7 +2307,7 @@
     }
     DartSdk sdk = factory.dartSdk;
     if (sdk == null) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "The source factory for an SDK analysis context must have a DartUriResolver");
     }
     return new AnalysisCache(
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index 0c9a84f..d6f5c15 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -143,8 +143,7 @@
   Source fromEncoding(String encoding) {
     Source source = forUri(encoding);
     if (source == null) {
-      throw new IllegalArgumentException(
-          "Invalid source encoding: '$encoding'");
+      throw new ArgumentError("Invalid source encoding: '$encoding'");
     }
     return source;
   }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 6be013c..90928c8 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -399,7 +399,7 @@
   void set correspondingPropagatedParameters(
       List<ParameterElement> parameters) {
     if (parameters != null && parameters.length != _arguments.length) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "Expected ${_arguments.length} parameters, not ${parameters.length}");
     }
     _correspondingPropagatedParameters = parameters;
@@ -411,7 +411,7 @@
   @override
   void set correspondingStaticParameters(List<ParameterElement> parameters) {
     if (parameters != null && parameters.length != _arguments.length) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "Expected ${_arguments.length} parameters, not ${parameters.length}");
     }
     _correspondingStaticParameters = parameters;
@@ -5177,7 +5177,7 @@
     }
     // This should never be reached because external functions must be named,
     // hence either the body or the name should be non-null.
-    throw new IllegalStateException("Non-external functions must have a body");
+    throw new StateError("Non-external functions must have a body");
   }
 
   @override
@@ -5201,7 +5201,7 @@
     }
     // This should never be reached because external functions must be named,
     // hence either the body or the name should be non-null.
-    throw new IllegalStateException("Non-external functions must have a body");
+    throw new StateError("Non-external functions must have a body");
   }
 
   @override
@@ -9297,7 +9297,7 @@
 
   @override
   void _appendStringValue(StringBuffer buffer) {
-    throw new IllegalArgumentException();
+    throw new ArgumentError();
   }
 }
 
@@ -9410,7 +9410,7 @@
     StringBuffer buffer = new StringBuffer();
     try {
       _appendStringValue(buffer);
-    } on IllegalArgumentException {
+    } on ArgumentError {
       return null;
     }
     return buffer.toString();
@@ -9418,8 +9418,8 @@
 
   /**
    * Append the value of this string literal to the given [buffer]. Throw an
-   * [IllegalArgumentException] if the string is not a constant string without
-   * any string interpolation.
+   * [ArgumentError] if the string is not a constant string without any
+   * string interpolation.
    */
   void _appendStringValue(StringBuffer buffer);
 }
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 59a51e9..2c0db3b 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -71,8 +71,7 @@
    * Return a list containing cloned versions of the nodes in the given list of
    * [nodes].
    */
-  List<AstNode/*=E*/ > cloneNodeList/*<E extends AstNode>*/(
-      List/*<E>*/ nodes) {
+  List<AstNode/*=E*/ > cloneNodeList/*<E extends AstNode>*/(List/*<E>*/ nodes) {
     int count = nodes.length;
     List/*<E>*/ clonedNodes = new List/*<E>*/();
     for (int i = 0; i < count; i++) {
@@ -936,6 +935,7 @@
     Token nonComment(Token token) {
       return token is CommentToken ? token.parent : token;
     }
+
     token = nonComment(token);
     if (_lastCloned == null) {
       _lastCloned = new Token(TokenType.EOF, -1);
@@ -4706,8 +4706,7 @@
   }
 
   bool visitNode(AstNode node) {
-    throw new IllegalArgumentException(
-        "The old node is not a child of it's parent");
+    throw new ArgumentError("The old node is not a child of it's parent");
   }
 
   bool visitNormalFormalParameter(NormalFormalParameter node) {
@@ -5065,21 +5064,18 @@
    * Replace the [oldNode] with the [newNode] in the AST structure containing
    * the old node. Return `true` if the replacement was successful.
    *
-   * Throws an [IllegalArgumentException] if either node is `null`, if the old
-   * node does not have a parent node, or if the AST structure has been
-   * corrupted.
+   * Throws an [ArgumentError] if either node is `null`, if the old node does
+   * not have a parent node, or if the AST structure has been corrupted.
    */
   static bool replace(AstNode oldNode, AstNode newNode) {
     if (oldNode == null || newNode == null) {
-      throw new IllegalArgumentException(
-          "The old and new nodes must be non-null");
+      throw new ArgumentError("The old and new nodes must be non-null");
     } else if (identical(oldNode, newNode)) {
       return true;
     }
     AstNode parent = oldNode.parent;
     if (parent == null) {
-      throw new IllegalArgumentException(
-          "The old node is not a child of another node");
+      throw new ArgumentError("The old node is not a child of another node");
     }
     NodeReplacer replacer = new NodeReplacer(oldNode, newNode);
     return parent.accept(replacer);
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index a0d1162..177e271 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -13,7 +13,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/utilities_general.dart';
 
@@ -240,7 +239,7 @@
       return new DartObjectImpl(typeProvider.stringType, result);
     }
     // We should never get here.
-    throw new IllegalStateException("add returned a ${result.runtimeType}");
+    throw new StateError("add returned a ${result.runtimeType}");
   }
 
   /**
@@ -339,7 +338,7 @@
       return new DartObjectImpl(typeProvider.numType, result);
     }
     // We should never get here.
-    throw new IllegalStateException("divide returned a ${result.runtimeType}");
+    throw new StateError("divide returned a ${result.runtimeType}");
   }
 
   /**
@@ -508,7 +507,7 @@
       return new DartObjectImpl(typeProvider.numType, result);
     }
     // We should never get here.
-    throw new IllegalStateException("minus returned a ${result.runtimeType}");
+    throw new StateError("minus returned a ${result.runtimeType}");
   }
 
   /**
@@ -528,7 +527,7 @@
       return new DartObjectImpl(typeProvider.numType, result);
     }
     // We should never get here.
-    throw new IllegalStateException("negated returned a ${result.runtimeType}");
+    throw new StateError("negated returned a ${result.runtimeType}");
   }
 
   /**
@@ -589,8 +588,7 @@
       return new DartObjectImpl(typeProvider.numType, result);
     }
     // We should never get here.
-    throw new IllegalStateException(
-        "remainder returned a ${result.runtimeType}");
+    throw new StateError("remainder returned a ${result.runtimeType}");
   }
 
   /**
@@ -647,7 +645,7 @@
       return new DartObjectImpl(typeProvider.numType, result);
     }
     // We should never get here.
-    throw new IllegalStateException("times returned a ${result.runtimeType}");
+    throw new StateError("times returned a ${result.runtimeType}");
   }
 
   @override
@@ -1231,9 +1229,9 @@
 }
 
 /**
- * A run-time exception that would be thrown during the evaluation of Dart code.
+ * Exception that would be thrown during the evaluation of Dart code.
  */
-class EvaluationException extends JavaException {
+class EvaluationException {
   /**
    * The error code associated with the exception.
    */
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 491025e..820a132 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -6442,16 +6442,41 @@
   String _name;
 
   /**
-   * A list containing all of the elements that conflict.
+   * A list containing all of the elements defined in SDK libraries that
+   * conflict.
    */
-  final List<Element> conflictingElements;
+  final List<Element> sdkElements;
+
+  /**
+   * A list containing all of the elements defined in non-SDK libraries that
+   * conflict.
+   */
+  final List<Element> nonSdkElements;
 
   /**
    * Initialize a newly created element in the given [context] to represent a
-   * list of [conflictingElements].
+   * list of conflicting [sdkElements] and [nonSdkElements]. At least one of the
+   * lists must contain more than one element.
    */
-  MultiplyDefinedElementImpl(this.context, this.conflictingElements) {
-    _name = conflictingElements[0].name;
+  MultiplyDefinedElementImpl(
+      this.context, this.sdkElements, this.nonSdkElements) {
+    if (nonSdkElements.length > 0) {
+      _name = nonSdkElements[0].name;
+    } else {
+      _name = sdkElements[0].name;
+    }
+  }
+
+  @override
+  List<Element> get conflictingElements {
+    if (sdkElements.isEmpty) {
+      return nonSdkElements;
+    } else if (nonSdkElements.isEmpty) {
+      return sdkElements;
+    }
+    List<Element> elements = nonSdkElements.toList();
+    elements.addAll(sdkElements);
+    return elements;
   }
 
   @override
@@ -6567,19 +6592,25 @@
   @override
   String toString() {
     StringBuffer buffer = new StringBuffer();
-    buffer.write("[");
-    int count = conflictingElements.length;
-    for (int i = 0; i < count; i++) {
-      if (i > 0) {
-        buffer.write(", ");
-      }
-      Element element = conflictingElements[i];
-      if (element is ElementImpl) {
-        element.appendTo(buffer);
-      } else {
-        buffer.write(element);
+    bool needsSeparator = false;
+    void writeList(List<Element> elements) {
+      for (Element element in elements) {
+        if (needsSeparator) {
+          buffer.write(", ");
+        } else {
+          needsSeparator = true;
+        }
+        if (element is ElementImpl) {
+          element.appendTo(buffer);
+        } else {
+          buffer.write(element);
+        }
       }
     }
+
+    buffer.write("[");
+    writeList(nonSdkElements);
+    writeList(sdkElements);
     buffer.write("]");
     return buffer.toString();
   }
@@ -6596,44 +6627,38 @@
    */
   static Element fromElements(
       AnalysisContext context, Element firstElement, Element secondElement) {
-    List<Element> conflictingElements =
-        _computeConflictingElements(firstElement, secondElement);
-    int length = conflictingElements.length;
-    if (length == 0) {
-      return null;
-    } else if (length == 1) {
-      return conflictingElements[0];
-    }
-    return new MultiplyDefinedElementImpl(context, conflictingElements);
-  }
-
-  /**
-   * Add the given [element] to the list of [elements]. If the element is a
-   * multiply-defined element, add all of the conflicting elements that it
-   * represents.
-   */
-  static void _add(HashSet<Element> elements, Element element) {
-    if (element is MultiplyDefinedElementImpl) {
-      for (Element conflictingElement in element.conflictingElements) {
-        elements.add(conflictingElement);
+    Set<Element> sdkElements = new HashSet<Element>.identity();
+    Set<Element> nonSdkElements = new HashSet<Element>.identity();
+    void add(Element element) {
+      if (element != null) {
+        if (element is MultiplyDefinedElementImpl) {
+          sdkElements.addAll(element.sdkElements);
+          nonSdkElements.addAll(element.nonSdkElements);
+        } else if (element.library.isInSdk) {
+          sdkElements.add(element);
+        } else {
+          nonSdkElements.add(element);
+        }
       }
-    } else {
-      elements.add(element);
     }
-  }
 
-  /**
-   * Use the given elements to construct a list of conflicting elements. If
-   * either the [firstElement] or [secondElement] are multiply-defined elements
-   * then the conflicting elements they represent will be included in the array.
-   * Otherwise, the element itself will be included.
-   */
-  static List<Element> _computeConflictingElements(
-      Element firstElement, Element secondElement) {
-    HashSet<Element> elements = new HashSet<Element>();
-    _add(elements, firstElement);
-    _add(elements, secondElement);
-    return elements.toList(growable: false);
+    add(firstElement);
+    add(secondElement);
+    int nonSdkCount = nonSdkElements.length;
+    if (nonSdkCount == 0) {
+      int sdkCount = sdkElements.length;
+      if (sdkCount == 0) {
+        return null;
+      } else if (sdkCount == 1) {
+        return sdkElements.first;
+      }
+    } else if (nonSdkCount == 1) {
+      return nonSdkElements.first;
+    }
+    return new MultiplyDefinedElementImpl(
+        context,
+        sdkElements.toList(growable: false),
+        nonSdkElements.toList(growable: false));
   }
 }
 
@@ -8389,7 +8414,7 @@
    * constant expression to the given [result].
    */
   void set evaluationResult(EvaluationResultImpl result) {
-    throw new IllegalStateException(
+    throw new StateError(
         "Invalid attempt to set a compile-time constant result");
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 4c95b28..e309af2 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -149,7 +149,7 @@
     // Elements within this element should have type parameters substituted,
     // just like this element.
     //
-    throw new UnsupportedOperationException();
+    throw new UnsupportedError('functions');
 //    return getBaseElement().getFunctions();
   }
 
@@ -186,7 +186,7 @@
     // Elements within this element should have type parameters substituted,
     // just like this element.
     //
-    throw new UnsupportedOperationException();
+    throw new UnsupportedError('localVariables');
 //    return getBaseElement().getLocalVariables();
   }
 
@@ -953,20 +953,20 @@
   Element get enclosingElement => baseElement.enclosingElement;
 
   @override
-  TypeParameterType get type => _type;
-
-  @override
-  accept(ElementVisitor visitor) => visitor.visitTypeParameterElement(this);
-
-  @override
   int get hashCode => baseElement.hashCode;
 
   @override
+  TypeParameterType get type => _type;
+
+  @override
   bool operator ==(obj) =>
       // TODO(jmesserly): this equality should consider the bound, see:
       // https://github.com/dart-lang/sdk/issues/27210
       obj is TypeParameterMember && obj.baseElement == baseElement;
 
+  @override
+  accept(ElementVisitor visitor) => visitor.visitTypeParameterElement(this);
+
   /**
    * If the given [parameter]'s type is different when any type parameters from
    * the defining type's declaration are replaced with the actual type
@@ -1033,7 +1033,7 @@
     // Elements within this element should have type parameters substituted,
     // just like this element.
     //
-    throw new UnsupportedOperationException();
+    throw new UnsupportedError('initializer');
     //    return getBaseElement().getInitializer();
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 2c59228..de73679 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -711,6 +711,7 @@
         needsComma = true;
       }
     }
+
     void startOptionalParameters() {
       if (needsComma) {
         buffer.write(", ");
@@ -759,7 +760,7 @@
   @override
   FunctionTypeImpl instantiate(List<DartType> argumentTypes) {
     if (argumentTypes.length != typeFormals.length) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "argumentTypes.length (${argumentTypes.length}) != "
           "typeFormals.length (${typeFormals.length})");
     }
@@ -838,7 +839,7 @@
     // substituting once.
     assert(this.prunedTypedefs == null);
     if (argumentTypes.length != parameterTypes.length) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})");
     }
     Element element = this.element;
@@ -1849,7 +1850,7 @@
       List<DartType> argumentTypes, List<DartType> parameterTypes,
       [List<FunctionTypeAliasElement> prune]) {
     if (argumentTypes.length != parameterTypes.length) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})");
     }
     if (argumentTypes.length == 0 || typeArguments.length == 0) {
@@ -1936,6 +1937,7 @@
         visitedClasses.remove(type.element);
       }
     }
+
     recurse(this);
     return result;
   }
@@ -1959,7 +1961,25 @@
     List<InterfaceType> s = _intersection(si, sj);
     return computeTypeAtMaxUniqueDepth(s);
   }
-  
+
+  /**
+   * Return the length of the longest inheritance path from the given [type] to
+   * Object.
+   *
+   * See [computeLeastUpperBound].
+   */
+  static int computeLongestInheritancePathToObject(InterfaceType type) =>
+      _computeLongestInheritancePathToObject(
+          type, 0, new HashSet<ClassElement>());
+
+  /**
+   * Returns the set of all superinterfaces of the given [type].
+   *
+   * See [computeLeastUpperBound].
+   */
+  static Set<InterfaceType> computeSuperinterfaceSet(InterfaceType type) =>
+      _computeSuperinterfaceSet(type, new HashSet<InterfaceType>());
+
   /**
    * Return the type from the [types] list that has the longest inheritence path
    * to Object of unique length.
@@ -1996,24 +2016,6 @@
   }
 
   /**
-   * Return the length of the longest inheritance path from the given [type] to
-   * Object.
-   *
-   * See [computeLeastUpperBound].
-   */
-  static int computeLongestInheritancePathToObject(InterfaceType type) =>
-      _computeLongestInheritancePathToObject(
-          type, 0, new HashSet<ClassElement>());
-
-  /**
-   * Returns the set of all superinterfaces of the given [type].
-   *
-   * See [computeLeastUpperBound].
-   */
-  static Set<InterfaceType> computeSuperinterfaceSet(InterfaceType type) =>
-      _computeSuperinterfaceSet(type, new HashSet<InterfaceType>());
-
-  /**
    * If there is a single type which is at least as specific as all of the
    * types in [types], return it.  Otherwise return `null`.
    */
@@ -2187,7 +2189,7 @@
     ClassElement firstElement = firstType.element;
     ClassElement secondElement = secondType.element;
     if (firstElement != secondElement) {
-      throw new IllegalArgumentException('The same elements expected, but '
+      throw new ArgumentError('The same elements expected, but '
           '$firstElement and $secondElement are given.');
     }
     if (firstType == secondType) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index 6c46c8c..dbe05b1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -25,7 +25,7 @@
    */
   BlockScope(Scope enclosingScope, Block block) : super(enclosingScope) {
     if (block == null) {
-      throw new IllegalArgumentException("block cannot be null");
+      throw new ArgumentError("block cannot be null");
     }
     _defineElements(block);
   }
@@ -69,7 +69,7 @@
   ClassScope(Scope enclosingScope, ClassElement classElement)
       : super(enclosingScope) {
     if (classElement == null) {
-      throw new IllegalArgumentException("class element cannot be null");
+      throw new ArgumentError("class element cannot be null");
     }
     _defineMembers(classElement);
   }
@@ -128,6 +128,7 @@
    */
   EnclosedScope(this.enclosingScope);
 
+  @deprecated
   @override
   AnalysisErrorListener get errorListener => enclosingScope.errorListener;
 
@@ -143,7 +144,7 @@
   }
 
   @override
-  Element _internalLookupPrefixed(Identifier identifier, String prefix,
+  Element _internalLookupPrefixed(PrefixedIdentifier identifier, String prefix,
       String name, LibraryElement referencingLibrary) {
     return enclosingScope._internalLookupPrefixed(
         identifier, prefix, name, referencingLibrary);
@@ -172,7 +173,7 @@
   FunctionScope(Scope enclosingScope, this._functionElement)
       : super(new EnclosedScope(new EnclosedScope(enclosingScope))) {
     if (_functionElement == null) {
-      throw new IllegalArgumentException("function element cannot be null");
+      throw new ArgumentError("function element cannot be null");
     }
     _defineTypeParameters();
   }
@@ -352,13 +353,18 @@
  */
 class LibraryImportScope extends Scope {
   /**
+   * The name of the property containing a list of the elements from the SDK
+   * that conflict with the single name imported from non-SDK libraries. The
+   * value of the property is always of type `List<Element>`.
+   */
+  static const String conflictingSdkElements = 'conflictingSdkElements';
+
+  /**
    * The element representing the library in which this scope is enclosed.
    */
   final LibraryElement _definingLibrary;
 
-  /**
-   * The listener that is to be informed when an error is encountered.
-   */
+  @deprecated
   @override
   final AnalysisErrorListener errorListener;
 
@@ -376,10 +382,10 @@
 
   /**
    * Initialize a newly created scope representing the names imported into the
-   * [_definingLibrary]. The [errorListener] is the listener that is to be
-   * informed when an error is encountered.
+   * [_definingLibrary]. The [errorListener] is no longer used and should be
+   * omitted.
    */
-  LibraryImportScope(this._definingLibrary, this.errorListener) {
+  LibraryImportScope(this._definingLibrary, [this.errorListener]) {
     _createImportedNamespaces();
   }
 
@@ -402,49 +408,16 @@
   @override
   Element internalLookup(
       Identifier identifier, String name, LibraryElement referencingLibrary) {
-    Element foundElement = localLookup(name, referencingLibrary);
-    if (foundElement != null) {
-      return foundElement;
+    Element element = localLookup(name, referencingLibrary);
+    if (element != null) {
+      return element;
     }
-    for (int i = 0; i < _importedNamespaces.length; i++) {
-      Namespace nameSpace = _importedNamespaces[i];
-      Element element = nameSpace.get(name);
-      if (element != null) {
-        if (foundElement == null) {
-          foundElement = element;
-        } else if (!identical(foundElement, element)) {
-          foundElement = MultiplyDefinedElementImpl.fromElements(
-              _definingLibrary.context, foundElement, element);
-        }
-      }
+    element = _lookupInImportedNamespaces(
+        identifier, (Namespace namespace) => namespace.get(name));
+    if (element != null) {
+      defineNameWithoutChecking(name, element);
     }
-    Element element = foundElement;
-    if (element is MultiplyDefinedElementImpl) {
-      foundElement = _removeSdkElements(identifier, name, element);
-    }
-    if (foundElement is MultiplyDefinedElementImpl) {
-      String foundEltName = foundElement.displayName;
-      List<Element> conflictingMembers = foundElement.conflictingElements;
-      int count = conflictingMembers.length;
-      List<String> libraryNames = new List<String>(count);
-      for (int i = 0; i < count; i++) {
-        libraryNames[i] = _getLibraryName(conflictingMembers[i]);
-      }
-      libraryNames.sort();
-      errorListener.onError(new AnalysisError(
-          getSource(identifier),
-          identifier.offset,
-          identifier.length,
-          StaticWarningCode.AMBIGUOUS_IMPORT, [
-        foundEltName,
-        StringUtilities.printListOfQuotedNames(libraryNames)
-      ]));
-      return foundElement;
-    }
-    if (foundElement != null) {
-      defineNameWithoutChecking(name, foundElement);
-    }
-    return foundElement;
+    return element;
   }
 
   @override
@@ -522,98 +495,19 @@
     unprefixedNames[name] = element;
   }
 
-  /**
-   * Return the name of the library that defines given [element].
-   */
-  String _getLibraryName(Element element) {
-    if (element == null) {
-      return StringUtilities.EMPTY;
-    }
-    LibraryElement library = element.library;
-    if (library == null) {
-      return StringUtilities.EMPTY;
-    }
-    List<ImportElement> imports = _definingLibrary.imports;
-    int count = imports.length;
-    for (int i = 0; i < count; i++) {
-      if (identical(imports[i].importedLibrary, library)) {
-        return library.definingCompilationUnit.displayName;
-      }
-    }
-    List<String> indirectSources = new List<String>();
-    for (int i = 0; i < count; i++) {
-      LibraryElement importedLibrary = imports[i].importedLibrary;
-      if (importedLibrary != null) {
-        for (LibraryElement exportedLibrary
-            in importedLibrary.exportedLibraries) {
-          if (identical(exportedLibrary, library)) {
-            indirectSources
-                .add(importedLibrary.definingCompilationUnit.displayName);
-          }
-        }
-      }
-    }
-    int indirectCount = indirectSources.length;
-    StringBuffer buffer = new StringBuffer();
-    buffer.write(library.definingCompilationUnit.displayName);
-    if (indirectCount > 0) {
-      buffer.write(" (via ");
-      if (indirectCount > 1) {
-        indirectSources.sort();
-        buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
-      } else {
-        buffer.write(indirectSources[0]);
-      }
-      buffer.write(")");
-    }
-    return buffer.toString();
-  }
-
   @override
-  Element _internalLookupPrefixed(Identifier identifier, String prefix,
+  Element _internalLookupPrefixed(PrefixedIdentifier identifier, String prefix,
       String name, LibraryElement referencingLibrary) {
-    Element foundElement = _localPrefixedLookup(prefix, name);
-    if (foundElement != null) {
-      return foundElement;
+    Element element = _localPrefixedLookup(prefix, name);
+    if (element != null) {
+      return element;
     }
-    for (int i = 0; i < _importedNamespaces.length; i++) {
-      Element element = _importedNamespaces[i].getPrefixed(prefix, name);
-      if (element != null) {
-        if (foundElement == null) {
-          foundElement = element;
-        } else if (!identical(foundElement, element)) {
-          foundElement = MultiplyDefinedElementImpl.fromElements(
-              _definingLibrary.context, foundElement, element);
-        }
-      }
+    element = _lookupInImportedNamespaces(identifier.identifier,
+        (Namespace namespace) => namespace.getPrefixed(prefix, name));
+    if (element != null) {
+      _definePrefixedNameWithoutChecking(prefix, name, element);
     }
-    Element element = foundElement;
-    if (element is MultiplyDefinedElementImpl) {
-      foundElement = _removeSdkElements(identifier, name, element);
-    }
-    if (foundElement is MultiplyDefinedElementImpl) {
-      String foundEltName = foundElement.displayName;
-      List<Element> conflictingMembers = foundElement.conflictingElements;
-      int count = conflictingMembers.length;
-      List<String> libraryNames = new List<String>(count);
-      for (int i = 0; i < count; i++) {
-        libraryNames[i] = _getLibraryName(conflictingMembers[i]);
-      }
-      libraryNames.sort();
-      errorListener.onError(new AnalysisError(
-          getSource(identifier),
-          identifier.offset,
-          identifier.length,
-          StaticWarningCode.AMBIGUOUS_IMPORT, [
-        foundEltName,
-        StringUtilities.printListOfQuotedNames(libraryNames)
-      ]));
-      return foundElement;
-    }
-    if (foundElement != null) {
-      _definePrefixedNameWithoutChecking(prefix, name, foundElement);
-    }
-    return foundElement;
+    return element;
   }
 
   /**
@@ -630,47 +524,40 @@
     return null;
   }
 
-  /**
-   * Given a collection of elements (captured by the [foundElement]) that the
-   * [identifier] (with the given [name]) resolved to, remove from the list all
-   * of the names defined in the SDK and return the element(s) that remain.
-   */
-  Element _removeSdkElements(Identifier identifier, String name,
-      MultiplyDefinedElementImpl foundElement) {
-    List<Element> conflictingElements = foundElement.conflictingElements;
-    List<Element> nonSdkElements = new List<Element>();
-    Element sdkElement = null;
-    for (Element member in conflictingElements) {
-      if (member.library.isInSdk) {
-        sdkElement = member;
-      } else {
-        nonSdkElements.add(member);
+  Element _lookupInImportedNamespaces(
+      Identifier identifier, Element lookup(Namespace namespace)) {
+    Set<Element> sdkElements = new HashSet<Element>();
+    Set<Element> nonSdkElements = new HashSet<Element>();
+    for (int i = 0; i < _importedNamespaces.length; i++) {
+      Element element = lookup(_importedNamespaces[i]);
+      if (element != null) {
+        if (element.library.isInSdk) {
+          sdkElements.add(element);
+        } else {
+          nonSdkElements.add(element);
+        }
       }
     }
-    if (sdkElement != null && nonSdkElements.length > 0) {
-      String sdkLibName = _getLibraryName(sdkElement);
-      String otherLibName = _getLibraryName(nonSdkElements[0]);
-      errorListener.onError(new AnalysisError(
-          getSource(identifier),
-          identifier.offset,
-          identifier.length,
-          StaticWarningCode.CONFLICTING_DART_IMPORT,
-          [name, sdkLibName, otherLibName]));
+    int nonSdkCount = nonSdkElements.length;
+    int sdkCount = sdkElements.length;
+    if (nonSdkCount == 0) {
+      if (sdkCount == 0) {
+        return null;
+      } else if (sdkCount == 1) {
+        return sdkElements.first;
+      }
     }
-    if (nonSdkElements.length == conflictingElements.length) {
-      // None of the members were removed
-      return foundElement;
-    } else if (nonSdkElements.length == 1) {
-      // All but one member was removed
-      return nonSdkElements[0];
-    } else if (nonSdkElements.length == 0) {
-      // All members were removed
-      AnalysisEngine.instance.logger
-          .logInformation("Multiply defined SDK element: $foundElement");
-      return foundElement;
+    if (nonSdkCount == 1) {
+      if (sdkCount > 0) {
+        identifier.setProperty(
+            conflictingSdkElements, sdkElements.toList(growable: false));
+      }
+      return nonSdkElements.first;
     }
     return new MultiplyDefinedElementImpl(
-        _definingLibrary.context, nonSdkElements);
+        _definingLibrary.context,
+        sdkElements.toList(growable: false),
+        nonSdkElements.toList(growable: false));
   }
 }
 
@@ -680,11 +567,11 @@
 class LibraryScope extends EnclosedScope {
   /**
    * Initialize a newly created scope representing the names defined in the
-   * [definingLibrary]. The [errorListener] is the listener that is to be
-   * informed when an error is encountered
+   * [definingLibrary]. The [errorListener] is no longer used and should be
+   * omitted.
    */
-  LibraryScope(
-      LibraryElement definingLibrary, AnalysisErrorListener errorListener)
+  LibraryScope(LibraryElement definingLibrary,
+      [@deprecated AnalysisErrorListener errorListener])
       : super(new LibraryImportScope(definingLibrary, errorListener)) {
     _defineTopLevelNames(definingLibrary);
   }
@@ -1103,6 +990,7 @@
   /**
    * Return the listener that is to be informed when an error is encountered.
    */
+  @deprecated
   AnalysisErrorListener get errorListener;
 
   /**
@@ -1245,7 +1133,7 @@
    * that contains the reference to the name, used to implement library-level
    * privacy.
    */
-  Element _internalLookupPrefixed(Identifier identifier, String prefix,
+  Element _internalLookupPrefixed(PrefixedIdentifier identifier, String prefix,
       String name, LibraryElement referencingLibrary);
 
   /**
@@ -1266,7 +1154,7 @@
   TypeParameterScope(Scope enclosingScope, ClassElement classElement)
       : super(enclosingScope) {
     if (classElement == null) {
-      throw new IllegalArgumentException("class element cannot be null");
+      throw new ArgumentError("class element cannot be null");
     }
     _defineTypeParameters(classElement);
   }
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 97150fc..e70c1d8 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -2453,9 +2453,11 @@
     } else if (element == null &&
         (identifier.inSetterContext() ||
             identifier.parent is CommentReference)) {
-      element = _resolver.nameScope.lookup(
-          new SyntheticIdentifier("${identifier.name}=", identifier),
-          _definingLibrary);
+      Identifier setterId =
+          new SyntheticIdentifier('${identifier.name}=', identifier);
+      element = _resolver.nameScope.lookup(setterId, _definingLibrary);
+      identifier.setProperty(LibraryImportScope.conflictingSdkElements,
+          setterId.getProperty(LibraryImportScope.conflictingSdkElements));
     }
     ClassElement enclosingClass = _resolver.enclosingClass;
     if (element == null && enclosingClass != null) {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 7e0f08a..8975ccd 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -227,7 +227,7 @@
    * analysis results that have been invalidated by these changes will be
    * removed.
    */
-  ApplyChangesStatus applyChanges(ChangeSet changeSet);
+  void applyChanges(ChangeSet changeSet);
 
   /**
    * Return the documentation comment for the given [element] as it appears in
@@ -1513,18 +1513,6 @@
 }
 
 /**
- * The result of applying a [ChangeSet] to a [AnalysisContext].
- */
-class ApplyChangesStatus {
-  /**
-   * Is `true` if the given [ChangeSet] caused any changes in the context.
-   */
-  final bool hasChanges;
-
-  ApplyChangesStatus(this.hasChanges);
-}
-
-/**
  * Statistics about cache consistency validation.
  */
 class CacheConsistencyValidationStatistics {
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 83ab38a..630c910 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -3202,9 +3202,9 @@
    */
   ErrorReporter(this._errorListener, this._defaultSource) {
     if (_errorListener == null) {
-      throw new IllegalArgumentException("An error listener must be provided");
+      throw new ArgumentError("An error listener must be provided");
     } else if (_defaultSource == null) {
-      throw new IllegalArgumentException("A default source must be provided");
+      throw new ArgumentError("A default source must be provided");
     }
     this._source = _defaultSource;
   }
@@ -4774,7 +4774,7 @@
    * Parameters:
    * 0: the ambiguous name
    * 1: the name of the dart: library in which the element is found
-   * 1: the name of the non-dart: library in which the element is found
+   * 2: the name of the non-dart: library in which the element is found
    */
   static const StaticWarningCode CONFLICTING_DART_IMPORT =
       const StaticWarningCode('CONFLICTING_DART_IMPORT',
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index bab17da..717ef2a 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1127,6 +1127,7 @@
 
   @override
   Object visitSimpleIdentifier(SimpleIdentifier node) {
+    _checkForAmbiguousImport(node);
     _checkForReferenceBeforeDeclaration(node);
     _checkForImplicitThisReferenceInInitializer(node);
     if (!_isUnqualifiedReferenceToNonLocalStaticMemberAllowed(node)) {
@@ -2336,6 +2337,37 @@
   }
 
   /**
+   * Check the given node to see whether it was ambiguous because the name was
+   * imported from two or more imports.
+   */
+  void _checkForAmbiguousImport(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is MultiplyDefinedElementImpl) {
+      String name = element.displayName;
+      List<Element> conflictingMembers = element.conflictingElements;
+      int count = conflictingMembers.length;
+      List<String> libraryNames = new List<String>(count);
+      for (int i = 0; i < count; i++) {
+        libraryNames[i] = _getLibraryName(conflictingMembers[i]);
+      }
+      libraryNames.sort();
+      _errorReporter.reportErrorForNode(StaticWarningCode.AMBIGUOUS_IMPORT,
+          node, [name, StringUtilities.printListOfQuotedNames(libraryNames)]);
+    } else {
+      List<Element> sdkElements =
+          node.getProperty(LibraryImportScope.conflictingSdkElements);
+      if (sdkElements != null) {
+        _errorReporter.reportErrorForNode(
+            StaticWarningCode.CONFLICTING_DART_IMPORT, node, [
+          element.displayName,
+          _getLibraryName(sdkElements[0]),
+          _getLibraryName(element)
+        ]);
+      }
+    }
+  }
+
+  /**
    * Verify that the given [expression] can be assigned to its corresponding
    * parameters. The [expectedStaticType] is the expected static type of the
    * parameter. The [actualStaticType] is the actual static type of the
@@ -6273,6 +6305,53 @@
     }
   }
 
+  /**
+   * Return the name of the library that defines given [element].
+   */
+  String _getLibraryName(Element element) {
+    if (element == null) {
+      return StringUtilities.EMPTY;
+    }
+    LibraryElement library = element.library;
+    if (library == null) {
+      return StringUtilities.EMPTY;
+    }
+    List<ImportElement> imports = _currentLibrary.imports;
+    int count = imports.length;
+    for (int i = 0; i < count; i++) {
+      if (identical(imports[i].importedLibrary, library)) {
+        return library.definingCompilationUnit.displayName;
+      }
+    }
+    List<String> indirectSources = new List<String>();
+    for (int i = 0; i < count; i++) {
+      LibraryElement importedLibrary = imports[i].importedLibrary;
+      if (importedLibrary != null) {
+        for (LibraryElement exportedLibrary
+            in importedLibrary.exportedLibraries) {
+          if (identical(exportedLibrary, library)) {
+            indirectSources
+                .add(importedLibrary.definingCompilationUnit.displayName);
+          }
+        }
+      }
+    }
+    int indirectCount = indirectSources.length;
+    StringBuffer buffer = new StringBuffer();
+    buffer.write(library.definingCompilationUnit.displayName);
+    if (indirectCount > 0) {
+      buffer.write(" (via ");
+      if (indirectCount > 1) {
+        indirectSources.sort();
+        buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
+      } else {
+        buffer.write(indirectSources[0]);
+      }
+      buffer.write(")");
+    }
+    return buffer.toString();
+  }
+
   ExecutableElement _getOverriddenMember(Element member) {
     if (member == null || _inheritanceManager == null) {
       return null;
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 9c6cbf8..85b0d31 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -1174,7 +1174,7 @@
       throw new AnalysisException(
           "Cannot create scope: compilation unit is not part of a library");
     }
-    return new LibraryScope(libraryElement, _errorListener);
+    return new LibraryScope(libraryElement);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index bedb35f..074bb3c 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -4,8 +4,6 @@
 
 library analyzer.src.generated.java_core;
 
-final Stopwatch nanoTimeStopwatch = new Stopwatch();
-
 /**
  * Inserts the given arguments into [pattern].
  *
@@ -86,8 +84,7 @@
         continue;
       }
       // unknown
-      throw new IllegalArgumentException(
-          '[$fmt][$i] = 0x${c.toRadixString(16)}');
+      throw new ArgumentError('[$fmt][$i] = 0x${c.toRadixString(16)}');
     } else {
       sb.writeCharCode(c);
     }
@@ -130,7 +127,7 @@
 
   static String toChars(int codePoint) {
     if (codePoint < 0 || codePoint > MAX_CODE_POINT) {
-      throw new IllegalArgumentException();
+      throw new ArgumentError();
     }
     if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) {
       return new String.fromCharCode(codePoint);
@@ -154,15 +151,6 @@
   String toString() => name;
 }
 
-class IllegalArgumentException extends JavaException {
-  IllegalArgumentException([message = "", cause = null])
-      : super(message, cause);
-}
-
-class IllegalStateException extends JavaException {
-  IllegalStateException([message = ""]) : super(message);
-}
-
 class JavaArrays {
   static int makeHashCode(List a) {
     // TODO(rnystrom): This is not used by analyzer, but is called by
@@ -178,18 +166,6 @@
   }
 }
 
-class JavaException implements Exception {
-  final String message;
-  final Object cause;
-  JavaException([this.message = "", this.cause = null]);
-  JavaException.withCause(this.cause) : message = null;
-  String toString() => "$runtimeType: $message $cause";
-}
-
-class JavaIOException extends JavaException {
-  JavaIOException([message = "", cause = null]) : super(message, cause);
-}
-
 class JavaPatternMatcher {
   Iterator<Match> _matches;
   Match _match;
@@ -224,39 +200,6 @@
   }
 }
 
-class JavaSystem {
-  static int currentTimeMillis() {
-    return (new DateTime.now()).millisecondsSinceEpoch;
-  }
-
-  static int nanoTime() {
-    if (!nanoTimeStopwatch.isRunning) {
-      nanoTimeStopwatch.start();
-    }
-    return nanoTimeStopwatch.elapsedMicroseconds * 1000;
-  }
-}
-
-class MissingFormatArgumentException implements Exception {
-  final String s;
-
-  MissingFormatArgumentException(this.s);
-
-  String toString() => "MissingFormatArgumentException: $s";
-}
-
-class NoSuchElementException extends JavaException {
-  String toString() => "NoSuchElementException";
-}
-
-class NotImplementedException extends JavaException {
-  NotImplementedException(message) : super(message);
-}
-
-class NumberFormatException extends JavaException {
-  String toString() => "NumberFormatException";
-}
-
 class PrintStringWriter extends PrintWriter {
   final StringBuffer _sb = new StringBuffer();
 
@@ -284,91 +227,6 @@
   }
 }
 
-class RuntimeException extends JavaException {
-  RuntimeException({String message: "", Exception cause: null})
-      : super(message, cause);
-}
-
-class StringIndexOutOfBoundsException extends JavaException {
-  StringIndexOutOfBoundsException(int index) : super('$index');
-}
-
-class StringUtils {
-  static String capitalize(String str) {
-    if (isEmpty(str)) {
-      return str;
-    }
-    return str.substring(0, 1).toUpperCase() + str.substring(1);
-  }
-
-  static bool equals(String cs1, String cs2) {
-    if (cs1 == cs2) {
-      return true;
-    }
-    if (cs1 == null || cs2 == null) {
-      return false;
-    }
-    return cs1 == cs2;
-  }
-
-  static bool isEmpty(String str) {
-    return str == null || str.isEmpty;
-  }
-
-  static String join(Iterable iter,
-      [String separator = ' ', int start = 0, int end = -1]) {
-    if (start != 0) {
-      iter = iter.skip(start);
-    }
-    if (end != -1) {
-      iter = iter.take(end - start);
-    }
-    return iter.join(separator);
-  }
-
-  static void printf(StringBuffer buffer, String fmt, List args) {
-    buffer.write(_printf(fmt, args));
-  }
-
-  static String remove(String str, String remove) {
-    if (isEmpty(str) || isEmpty(remove)) {
-      return str;
-    }
-    return str.replaceAll(remove, '');
-  }
-
-  static String removeStart(String str, String remove) {
-    if (isEmpty(str) || isEmpty(remove)) {
-      return str;
-    }
-    if (str.startsWith(remove)) {
-      return str.substring(remove.length);
-    }
-    return str;
-  }
-
-  static String repeat(String s, int n) {
-    StringBuffer sb = new StringBuffer();
-    for (int i = 0; i < n; i++) {
-      sb.write(s);
-    }
-    return sb.toString();
-  }
-
-  static List<String> split(String s, [String pattern = ' ']) {
-    return s.split(pattern);
-  }
-
-  static List<String> splitByWholeSeparatorPreserveAllTokens(
-      String s, String pattern) {
-    return s.split(pattern);
-  }
-}
-
-class UnsupportedOperationException extends JavaException {
-  UnsupportedOperationException([message = ""]) : super(message);
-}
-
 class URISyntaxException implements Exception {
   final String message;
   URISyntaxException(this.message);
diff --git a/pkg/analyzer/lib/src/generated/java_engine.dart b/pkg/analyzer/lib/src/generated/java_engine.dart
index be2020f..0190ddd 100644
--- a/pkg/analyzer/lib/src/generated/java_engine.dart
+++ b/pkg/analyzer/lib/src/generated/java_engine.dart
@@ -275,12 +275,11 @@
    */
   static String printListOfQuotedNames(List<String> names) {
     if (names == null) {
-      throw new IllegalArgumentException("The list must not be null");
+      throw new ArgumentError("The list must not be null");
     }
     int count = names.length;
     if (count < 2) {
-      throw new IllegalArgumentException(
-          "The list must contain at least two names");
+      throw new ArgumentError("The list must contain at least two names");
     }
     StringBuffer buffer = new StringBuffer();
     buffer.write("'");
diff --git a/pkg/analyzer/lib/src/generated/java_io.dart b/pkg/analyzer/lib/src/generated/java_io.dart
index 2e0deb1..9b07d6d 100644
--- a/pkg/analyzer/lib/src/generated/java_io.dart
+++ b/pkg/analyzer/lib/src/generated/java_io.dart
@@ -6,7 +6,6 @@
 
 import "dart:io";
 
-import 'package:analyzer/src/generated/java_core.dart' show JavaIOException;
 import 'package:path/path.dart' as path;
 
 class JavaFile {
@@ -51,11 +50,7 @@
 
   JavaFile getCanonicalFile() => new JavaFile(getCanonicalPath());
   String getCanonicalPath() {
-    try {
-      return _newFile().resolveSymbolicLinksSync();
-    } catch (e) {
-      throw new JavaIOException('IOException', e);
-    }
+    return _newFile().resolveSymbolicLinksSync();
   }
 
   String getName() => pathContext.basename(_path);
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 8e24b98..4eaece9 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -483,7 +483,7 @@
   MethodTrampoline method =
       methodTable_Parser['${methodName}_${objects.length}'];
   if (method == null) {
-    throw new IllegalArgumentException('There is no method named $methodName');
+    throw new ArgumentError('There is no method named $methodName');
   }
   return method.invoke(parser, objects);
 }
@@ -1670,7 +1670,7 @@
    * the node to be replaced.
    */
   AstNode _notAChild(AstNode node) {
-    throw new IncrementalParseException.con1(
+    throw new IncrementalParseException(
         "Internal error: the visited node (a ${node.runtimeType}) was not the parent of the node to be replaced (a ${_oldNode.runtimeType})");
   }
 }
@@ -1680,24 +1680,10 @@
  * specified node in an existing AST structure.
  */
 @deprecated
-class IncrementalParseException extends RuntimeException {
-  /**
-   * Initialize a newly created exception to have no message and to be its own
-   * cause.
-   */
-  IncrementalParseException() : super();
-
-  /**
-   * Initialize a newly created exception to have the given [message] and to be
-   * its own cause.
-   */
-  IncrementalParseException.con1(String message) : super(message: message);
-
-  /**
-   * Initialize a newly created exception to have no message and to have the
-   * given [cause].
-   */
-  IncrementalParseException.con2(Exception cause) : super(cause: cause);
+class IncrementalParseException {
+  final String message;
+  IncrementalParseException([this.message = '']);
+  String toString() => '$runtimeType: $message';
 }
 
 /**
@@ -1970,23 +1956,7 @@
  */
 @deprecated
 class InsufficientContextException extends IncrementalParseException {
-  /**
-   * Initialize a newly created exception to have no message and to be its own
-   * cause.
-   */
-  InsufficientContextException() : super();
-
-  /**
-   * Initialize a newly created exception to have the given [message] and to be
-   * its own cause.
-   */
-  InsufficientContextException.con1(String message) : super.con1(message);
-
-  /**
-   * Initialize a newly created exception to have no message and to have the
-   * given [cause].
-   */
-  InsufficientContextException.con2(Exception cause) : super.con2(cause);
+  InsufficientContextException([String message = '']) : super(message);
 }
 
 /**
@@ -1999,8 +1969,7 @@
   MethodTrampoline(this.parameterCount, this.trampoline);
   Object invoke(target, List arguments) {
     if (arguments.length != parameterCount) {
-      throw new IllegalArgumentException(
-          "${arguments.length} != $parameterCount");
+      throw new ArgumentError("${arguments.length} != $parameterCount");
     }
     switch (parameterCount) {
       case 0:
@@ -2015,7 +1984,7 @@
         return trampoline(
             target, arguments[0], arguments[1], arguments[2], arguments[3]);
       default:
-        throw new IllegalArgumentException("Not implemented for > 4 arguments");
+        throw new ArgumentError("Not implemented for > 4 arguments");
     }
   }
 }
@@ -2878,7 +2847,7 @@
           } else {
             // Internal error: this method should not have been invoked if the
             // current token was something other than one of the above.
-            throw new IllegalStateException(
+            throw new StateError(
                 "parseDirective invoked in an invalid state (currentToken = $_currentToken)");
           }
         }
@@ -5730,7 +5699,7 @@
     } else {
       // Internal error: this method should not have been invoked if the current
       // token was something other than one of the above.
-      throw new IllegalStateException(
+      throw new StateError(
           "parseDirective invoked in an invalid state; currentToken = $_currentToken");
     }
   }
@@ -9599,8 +9568,7 @@
    */
   void _unlockErrorListener() {
     if (_errorListenerLock == 0) {
-      throw new IllegalStateException(
-          "Attempt to unlock not locked error listener.");
+      throw new StateError("Attempt to unlock not locked error listener.");
     }
     _errorListenerLock--;
   }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 3ac1139..e26126f 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -64,6 +64,11 @@
   final ErrorReporter _errorReporter;
 
   /**
+   * The type [Null].
+   */
+  final InterfaceType _nullType;
+
+  /**
    * The type Future<Null>, which is needed for determining whether it is safe
    * to have a bare "return;" in an async method.
    */
@@ -87,7 +92,8 @@
   BestPracticesVerifier(
       this._errorReporter, TypeProvider typeProvider, this._currentLibrary,
       {TypeSystem typeSystem})
-      : _futureNullType = typeProvider.futureNullType,
+      : _nullType = typeProvider.nullType,
+        _futureNullType = typeProvider.futureNullType,
         _typeSystem = typeSystem ?? new TypeSystemImpl() {
     inDeprecatedMember = _currentLibrary.isDeprecated;
   }
@@ -275,7 +281,8 @@
 
   @override
   Object visitMethodInvocation(MethodInvocation node) {
-    _checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
+    _checkForCanBeNullAfterNullAware(
+        node.realTarget, node.operator, null, node.methodName);
     DartType staticInvokeType = node.staticInvokeType;
     if (staticInvokeType is InterfaceType) {
       MethodElement methodElement = staticInvokeType.lookUpMethod(
@@ -299,7 +306,8 @@
 
   @override
   Object visitPropertyAccess(PropertyAccess node) {
-    _checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
+    _checkForCanBeNullAfterNullAware(
+        node.realTarget, node.operator, node.propertyName, null);
     return super.visitPropertyAccess(node);
   }
 
@@ -521,20 +529,37 @@
   }
 
   /**
-   * Produce a hint if the given [target] could have a value of `null`.
+   * Produce a hint if the given [target] could have a value of `null`, and
+   * [identifier] is not a name of a getter or a method that exists in the
+   * class [Null].
    */
-  void _checkForCanBeNullAfterNullAware(Expression target, Token operator) {
+  void _checkForCanBeNullAfterNullAware(Expression target, Token operator,
+      SimpleIdentifier propertyName, SimpleIdentifier methodName) {
     if (operator?.type == TokenType.QUESTION_PERIOD) {
       return;
     }
+    bool isNullTypeMember() {
+      if (propertyName != null) {
+        String name = propertyName.name;
+        return _nullType.lookUpGetter(name, _currentLibrary) != null;
+      }
+      if (methodName != null) {
+        String name = methodName.name;
+        return _nullType.lookUpMethod(name, _currentLibrary) != null;
+      }
+      return false;
+    }
+
     target = target?.unParenthesized;
     if (target is MethodInvocation) {
-      if (target.operator?.type == TokenType.QUESTION_PERIOD) {
+      if (target.operator?.type == TokenType.QUESTION_PERIOD &&
+          !isNullTypeMember()) {
         _errorReporter.reportErrorForNode(
             HintCode.CAN_BE_NULL_AFTER_NULL_AWARE, target);
       }
     } else if (target is PropertyAccess) {
-      if (target.operator.type == TokenType.QUESTION_PERIOD) {
+      if (target.operator.type == TokenType.QUESTION_PERIOD &&
+          !isNullTypeMember()) {
         _errorReporter.reportErrorForNode(
             HintCode.CAN_BE_NULL_AFTER_NULL_AWARE, target);
       }
@@ -7745,7 +7770,7 @@
       : source = source,
         errorReporter = new ErrorReporter(errorListener, source) {
     if (nameScope == null) {
-      this.nameScope = new LibraryScope(definingLibrary, errorListener);
+      this.nameScope = new LibraryScope(definingLibrary);
     } else {
       this.nameScope = nameScope;
     }
@@ -9072,7 +9097,7 @@
    */
   void applyOverrides(Map<VariableElement, DartType> overrides) {
     if (currentScope == null) {
-      throw new IllegalStateException("Cannot apply overrides without a scope");
+      throw new StateError("Cannot apply overrides without a scope");
     }
     currentScope.applyOverrides(overrides);
   }
@@ -9085,8 +9110,7 @@
    */
   Map<VariableElement, DartType> captureLocalOverrides() {
     if (currentScope == null) {
-      throw new IllegalStateException(
-          "Cannot capture local overrides without a scope");
+      throw new StateError("Cannot capture local overrides without a scope");
     }
     return currentScope.captureLocalOverrides();
   }
@@ -9101,8 +9125,7 @@
   Map<VariableElement, DartType> captureOverrides(
       VariableDeclarationList variableList) {
     if (currentScope == null) {
-      throw new IllegalStateException(
-          "Cannot capture overrides without a scope");
+      throw new StateError("Cannot capture overrides without a scope");
     }
     return currentScope.captureOverrides(variableList);
   }
@@ -9119,7 +9142,7 @@
    */
   void exitScope() {
     if (currentScope == null) {
-      throw new IllegalStateException("No scope to exit");
+      throw new StateError("No scope to exit");
     }
     currentScope = currentScope._outerScope;
   }
@@ -9178,7 +9201,7 @@
    */
   void setType(VariableElement element, DartType type) {
     if (currentScope == null) {
-      throw new IllegalStateException("Cannot override without a scope");
+      throw new StateError("Cannot override without a scope");
     }
     currentScope.setType(element, type);
   }
@@ -9338,7 +9361,7 @@
                 library, LibraryResolutionCapability.resolvedTypeNames)) {
               bound.type = typeParameterElement.bound;
             } else {
-              libraryScope ??= new LibraryScope(library, errorListener);
+              libraryScope ??= new LibraryScope(library);
               typeParametersScope ??= createTypeParametersScope();
               typeNameResolver ??= new TypeNameResolver(new TypeSystemImpl(),
                   typeProvider, library, source, errorListener);
@@ -9380,7 +9403,7 @@
    */
   void exitScope() {
     if (currentScope == null) {
-      throw new IllegalStateException("No scope to exit");
+      throw new StateError("No scope to exit");
     }
     currentScope = currentScope._outerScope;
   }
@@ -9405,7 +9428,7 @@
    */
   void setType(Element element, DartType type) {
     if (currentScope == null) {
-      throw new IllegalStateException("Cannot promote without a scope");
+      throw new StateError("Cannot promote without a scope");
     }
     currentScope.setType(element, type);
   }
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 2d0acf5d..2fc6c2d 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -8,14 +8,14 @@
 import "dart:math" as math;
 
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
-import 'package:analyzer/src/generated/source_io.dart'
-    show FileBasedSource, PackageUriResolver;
+import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
 import 'package:analyzer/task/model.dart';
 import 'package:package_config/packages.dart';
 import 'package:path/path.dart' as pathos;
@@ -42,6 +42,8 @@
    */
   HashMap<String, int> _stampMap = new HashMap<String, int>();
 
+  int _nextStamp = 0;
+
   /**
    * Visit all entries of this cache.
    */
@@ -82,7 +84,7 @@
       _stampMap.remove(fullName);
       return _contentMap.remove(fullName);
     } else {
-      int newStamp = JavaSystem.currentTimeMillis();
+      int newStamp = _nextStamp++;
       int oldStamp = _stampMap[fullName];
       _stampMap[fullName] = newStamp;
       // Occasionally, if this method is called in rapid succession, the
@@ -98,6 +100,7 @@
   }
 }
 
+@deprecated
 class CustomUriResolver extends UriResolver {
   final Map<String, String> _urlMappings;
 
@@ -211,9 +214,9 @@
    */
   LineInfo._(this.lineStarts) {
     if (lineStarts == null) {
-      throw new IllegalArgumentException("lineStarts must be non-null");
+      throw new ArgumentError("lineStarts must be non-null");
     } else if (lineStarts.length < 1) {
-      throw new IllegalArgumentException("lineStarts must be non-empty");
+      throw new ArgumentError("lineStarts must be non-empty");
     }
   }
 
@@ -378,7 +381,7 @@
 
   @override
   TimestampedData<String> get contents {
-    throw new UnsupportedOperationException('$fullName does not exist.');
+    throw new UnsupportedError('$fullName does not exist.');
   }
 
   @override
@@ -900,7 +903,7 @@
    * Return the URI kind corresponding to the given scheme string.
    */
   static UriKind fromScheme(String scheme) {
-    if (scheme == PackageUriResolver.PACKAGE_SCHEME) {
+    if (scheme == PackageMapUriResolver.PACKAGE_SCHEME) {
       return UriKind.PACKAGE_URI;
     } else if (scheme == DartUriResolver.DART_SCHEME) {
       return UriKind.DART_URI;
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index f889078..f6af841 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -350,6 +350,7 @@
  * should be canonicalized, but to preserve relative links within a package, the remainder of the
  * path from the package directory to the leaf should not.
  */
+@deprecated
 class PackageUriResolver extends UriResolver {
   /**
    * The name of the `package` scheme.
@@ -375,7 +376,7 @@
    */
   PackageUriResolver(this._packagesDirectories) {
     if (_packagesDirectories.length < 1) {
-      throw new IllegalArgumentException(
+      throw new ArgumentError(
           "At least one package directory must be provided");
     }
   }
@@ -406,7 +407,7 @@
     JavaFile pkgDir = new JavaFile.relative(packagesDirectory, pkgName);
     try {
       pkgDir = pkgDir.getCanonicalFile();
-    } on JavaIOException catch (exception, stackTrace) {
+    } catch (exception, stackTrace) {
       if (!exception.toString().contains("Required key not available")) {
         AnalysisEngine.instance.logger.logError("Canonical failed: $pkgDir",
             new CaughtException(exception, stackTrace));
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 106977c..f0067a6 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -287,7 +287,7 @@
     int nameCount = names == null ? 0 : names.length;
     int typeCount = namedParameters == null ? 0 : namedParameters.length;
     if (names != null && nameCount != typeCount) {
-      throw new IllegalStateException(
+      throw new StateError(
           "The passed String[] and ClassElement[] arrays had different lengths.");
     }
     int totalCount = normalCount + nameCount;
diff --git a/pkg/analyzer/lib/src/generated/utilities_collection.dart b/pkg/analyzer/lib/src/generated/utilities_collection.dart
index a1f6cd6..cd39548 100644
--- a/pkg/analyzer/lib/src/generated/utilities_collection.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_collection.dart
@@ -203,7 +203,7 @@
    */
   List<N> findCycleContaining(N node) {
     if (node == null) {
-      throw new IllegalArgumentException();
+      throw new ArgumentError();
     }
     DirectedGraph_SccFinder<N> finder = new DirectedGraph_SccFinder<N>(this);
     return finder.componentContaining(node);
@@ -570,7 +570,7 @@
   @override
   K get key {
     if (_currentIterator == null) {
-      throw new NoSuchElementException();
+      throw new StateError('No element');
     }
     return _currentIterator.key;
   }
@@ -578,7 +578,7 @@
   @override
   V get value {
     if (_currentIterator == null) {
-      throw new NoSuchElementException();
+      throw new StateError('No element');
     }
     return _currentIterator.value;
   }
@@ -586,7 +586,7 @@
   @override
   void set value(V newValue) {
     if (_currentIterator == null) {
-      throw new NoSuchElementException();
+      throw new StateError('No element');
     }
     _currentIterator.value = newValue;
   }
@@ -672,7 +672,7 @@
   @override
   K get key {
     if (_currentKey == null) {
-      throw new NoSuchElementException();
+      throw new StateError('No element');
     }
     return _currentKey;
   }
@@ -680,7 +680,7 @@
   @override
   V get value {
     if (_currentKey == null) {
-      throw new NoSuchElementException();
+      throw new StateError('No element');
     }
     if (_currentValue == null) {
       _currentValue = _map[_currentKey];
@@ -691,7 +691,7 @@
   @override
   void set value(V newValue) {
     if (_currentKey == null) {
-      throw new NoSuchElementException();
+      throw new StateError('No element');
     }
     _currentValue = newValue;
     _map[_currentKey] = newValue;
diff --git a/pkg/analyzer/lib/src/summary/pub_summary.dart b/pkg/analyzer/lib/src/summary/pub_summary.dart
index ed7221a..3e1cfd7 100644
--- a/pkg/analyzer/lib/src/summary/pub_summary.dart
+++ b/pkg/analyzer/lib/src/summary/pub_summary.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -26,6 +27,8 @@
 import 'package:analyzer/src/summary/summarize_elements.dart'
     show PackageBundleAssembler;
 import 'package:analyzer/src/util/fast_uri.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as pathos;
 
@@ -80,6 +83,11 @@
   static const UNLINKED_NAME = 'unlinked.ds';
   static const UNLINKED_SPEC_NAME = 'unlinked_spec.ds';
 
+  /**
+   * See [PackageBundleAssembler.currentMajorVersion].
+   */
+  final int majorVersion;
+
   final ResourceProvider resourceProvider;
 
   /**
@@ -117,7 +125,9 @@
    */
   Completer _onUnlinkedCompleteCompleter;
 
-  PubSummaryManager(this.resourceProvider, this.tempFileName);
+  PubSummaryManager(this.resourceProvider, this.tempFileName,
+      {@visibleForTesting this.majorVersion:
+          PackageBundleAssembler.currentMajorVersion});
 
   /**
    * The [Future] that completes when computing of all scheduled unlinked
@@ -342,7 +352,9 @@
 
     try {
       addDartFiles(libFolder);
-      List<int> bytes = assembler.assemble().toBuffer();
+      PackageBundleBuilder bundleWriter = assembler.assemble();
+      bundleWriter.majorVersion = majorVersion;
+      List<int> bytes = bundleWriter.toBuffer();
       String fileName = _getUnlinkedName(strong);
       _writeAtomic(package.folder, fileName, bytes);
     } on FileSystemException {
@@ -382,31 +394,87 @@
     if (bundle != null) {
       return bundle;
     }
+
     // Try to read from the file system.
     String fileName = _getUnlinkedName(strong);
-    File unlinkedFile = package.folder.getChildAssumingFile(fileName);
-    if (unlinkedFile.exists) {
+    File file = package.folder.getChildAssumingFile(fileName);
+    if (file.exists) {
       try {
-        List<int> bytes = unlinkedFile.readAsBytesSync();
+        List<int> bytes = file.readAsBytesSync();
         bundle = new PackageBundle.fromBuffer(bytes);
-        unlinkedBundleMap[package] = bundle;
-        // TODO(scheglov) if not in the pub cache, check for consistency
-        return bundle;
       } on FileSystemException {
         // Ignore file system exceptions.
       }
     }
+
+    // Verify compatibility and consistency.
+    bool isInPubCache = isPathInPubCache(pathContext, package.folder.path);
+    if (bundle != null &&
+        bundle.majorVersion == majorVersion &&
+        (isInPubCache || _isConsistent(package, bundle))) {
+      unlinkedBundleMap[package] = bundle;
+      return bundle;
+    }
+
     // Schedule computation in the background, if in the pub cache.
-    if (isPathInPubCache(pathContext, package.folder.path)) {
+    if (isInPubCache) {
       if (seenPackages.add(package)) {
         _scheduleUnlinked(package);
       }
     }
-    // The bundle is for available.
+
+    // The bundle is not available.
     return null;
   }
 
   /**
+   * Return `true` if content hashes for the [package] library files are the
+   * same the hashes in the unlinked [bundle].
+   */
+  bool _isConsistent(PubPackage package, PackageBundle bundle) {
+    List<String> actualHashes = <String>[];
+
+    /**
+     * If the given [file] is a Dart file, add its content hash.
+     */
+    void hashDartFile(File file) {
+      String path = file.path;
+      if (AnalysisEngine.isDartFileName(path)) {
+        List<int> fileBytes = file.readAsBytesSync();
+        List<int> hashBytes = md5.convert(fileBytes).bytes;
+        String hashHex = hex.encode(hashBytes);
+        actualHashes.add(hashHex);
+      }
+    }
+
+    /**
+     * Visit the [folder] recursively.
+     */
+    void hashDartFiles(Folder folder) {
+      List<Resource> children = folder.getChildren();
+      for (Resource child in children) {
+        if (child is File) {
+          hashDartFile(child);
+        } else if (child is Folder) {
+          hashDartFiles(child);
+        }
+      }
+    }
+
+    // Recursively compute hashes of the `lib` folder Dart files.
+    try {
+      hashDartFiles(package.libFolder);
+    } on FileSystemException {
+      return false;
+    }
+
+    // Compare sorted actual and bundle unit hashes.
+    List<String> bundleHashes = bundle.unlinkedUnitHashes.toList()..sort();
+    actualHashes.sort();
+    return listsEqual(actualHashes, bundleHashes);
+  }
+
+  /**
    * Parse the given [source] into AST.
    */
   CompilationUnit _parse(Source source, bool strong) {
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 3683b7e..3c9c426 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -1596,10 +1596,12 @@
           context as InternalAnalysisContext;
       AnalysisCache analysisCache = internalContext.analysisCache;
       CacheEntry cacheEntry = internalContext.getCacheEntry(target);
-      libraryElement = analysisCache.getValue(target, LIBRARY_ELEMENT1) as LibraryElementImpl;
+      libraryElement = analysisCache.getValue(target, LIBRARY_ELEMENT1)
+          as LibraryElementImpl;
       if (libraryElement == null &&
           internalContext.aboutToComputeResult(cacheEntry, LIBRARY_ELEMENT1)) {
-        libraryElement = analysisCache.getValue(target, LIBRARY_ELEMENT1) as LibraryElementImpl;
+        libraryElement = analysisCache.getValue(target, LIBRARY_ELEMENT1)
+            as LibraryElementImpl;
       }
     }
     //
@@ -5773,7 +5775,7 @@
     // Resolve local variables.
     //
     RecordingErrorListener errorListener = new RecordingErrorListener();
-    Scope nameScope = new LibraryScope(libraryElement, errorListener);
+    Scope nameScope = new LibraryScope(libraryElement);
     VariableResolverVisitor visitor = new VariableResolverVisitor(
         libraryElement, unitElement.source, typeProvider, errorListener,
         nameScope: nameScope);
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index a2d003e..f47c957 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -1404,17 +1404,16 @@
     }
     FunctionType concreteSubType = subType;
     FunctionType concreteBaseType = baseType;
-    if (element is MethodElement) {
-      if (concreteSubType.typeFormals.isNotEmpty) {
-        if (concreteBaseType.typeFormals.isEmpty) {
-          concreteSubType = rules.instantiateToBounds(concreteSubType);
-        }
+    if (concreteSubType.typeFormals.isNotEmpty) {
+      if (concreteBaseType.typeFormals.isEmpty) {
+        concreteSubType = rules.instantiateToBounds(concreteSubType);
       }
-      concreteSubType =
-          rules.typeToConcreteType(_typeProvider, concreteSubType);
-      concreteBaseType =
-          rules.typeToConcreteType(_typeProvider, concreteBaseType);
     }
+    concreteSubType =
+        rules.typeToConcreteType(_typeProvider, concreteSubType);
+    concreteBaseType =
+        rules.typeToConcreteType(_typeProvider, concreteBaseType);
+
     if (!rules.isSubtypeOf(concreteSubType, concreteBaseType)) {
       // See whether non-subtype cases fit one of our common patterns:
       //
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 392e8cf..60e00e0 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -109,6 +109,7 @@
   }
 }
 
+@deprecated
 @reflectiveTest
 class CustomUriResolverTest {
   void test_creation() {
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 9cb90bf..a562940 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -12,8 +12,6 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
@@ -883,13 +881,8 @@
     _definingLibrary.definingCompilationUnit = unit;
     _visitor = new ResolverVisitor(
         _definingLibrary, source, _typeProvider, _listener,
-        nameScope: new LibraryScope(_definingLibrary, _listener));
-    try {
-      return _visitor.elementResolver;
-    } catch (exception) {
-      throw new IllegalArgumentException(
-          "Could not create resolver", exception);
-    }
+        nameScope: new LibraryScope(_definingLibrary));
+    return _visitor.elementResolver;
   }
 
   /**
@@ -943,21 +936,16 @@
    * @return the element to which the expression was resolved
    */
   void _resolveInClass(AstNode node, ClassElement enclosingClass) {
+    Scope outerScope = _visitor.nameScope;
     try {
-      Scope outerScope = _visitor.nameScope;
-      try {
-        _visitor.enclosingClass = enclosingClass;
-        EnclosedScope innerScope = new ClassScope(
-            new TypeParameterScope(outerScope, enclosingClass), enclosingClass);
-        _visitor.nameScope = innerScope;
-        node.accept(_resolver);
-      } finally {
-        _visitor.enclosingClass = null;
-        _visitor.nameScope = outerScope;
-      }
-    } catch (exception, stackTrace) {
-      throw new IllegalArgumentException(
-          "Could not resolve node", new CaughtException(exception, stackTrace));
+      _visitor.enclosingClass = enclosingClass;
+      EnclosedScope innerScope = new ClassScope(
+          new TypeParameterScope(outerScope, enclosingClass), enclosingClass);
+      _visitor.nameScope = innerScope;
+      node.accept(_resolver);
+    } finally {
+      _visitor.enclosingClass = null;
+      _visitor.nameScope = outerScope;
     }
   }
 
@@ -986,22 +974,18 @@
    * @return the element to which the expression was resolved
    */
   void _resolveNode(AstNode node, [List<Element> definedElements]) {
+    Scope outerScope = _visitor.nameScope;
     try {
-      Scope outerScope = _visitor.nameScope;
-      try {
-        EnclosedScope innerScope = new EnclosedScope(outerScope);
-        if (definedElements != null) {
-          for (Element element in definedElements) {
-            innerScope.define(element);
-          }
+      EnclosedScope innerScope = new EnclosedScope(outerScope);
+      if (definedElements != null) {
+        for (Element element in definedElements) {
+          innerScope.define(element);
         }
-        _visitor.nameScope = innerScope;
-        node.accept(_resolver);
-      } finally {
-        _visitor.nameScope = outerScope;
       }
-    } catch (exception) {
-      throw new IllegalArgumentException("Could not resolve node", exception);
+      _visitor.nameScope = innerScope;
+      node.accept(_resolver);
+    } finally {
+      _visitor.nameScope = outerScope;
     }
   }
 
@@ -1015,23 +999,19 @@
    */
   void _resolveStatement(
       Statement statement, LabelElementImpl labelElement, AstNode labelTarget) {
+    LabelScope outerScope = _visitor.labelScope;
     try {
-      LabelScope outerScope = _visitor.labelScope;
-      try {
-        LabelScope innerScope;
-        if (labelElement == null) {
-          innerScope = outerScope;
-        } else {
-          innerScope = new LabelScope(
-              outerScope, labelElement.name, labelTarget, labelElement);
-        }
-        _visitor.labelScope = innerScope;
-        statement.accept(_resolver);
-      } finally {
-        _visitor.labelScope = outerScope;
+      LabelScope innerScope;
+      if (labelElement == null) {
+        innerScope = outerScope;
+      } else {
+        innerScope = new LabelScope(
+            outerScope, labelElement.name, labelTarget, labelElement);
       }
-    } catch (exception) {
-      throw new IllegalArgumentException("Could not resolve node", exception);
+      _visitor.labelScope = innerScope;
+      statement.accept(_resolver);
+    } finally {
+      _visitor.labelScope = outerScope;
     }
   }
 }
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index 1e3ec09..f62c1b9 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -81,7 +81,7 @@
 class MockSourceFactory extends SourceFactoryImpl {
   MockSourceFactory() : super([]);
   Source resolveUri(Source containingSource, String containedUri) {
-    throw new JavaIOException();
+    throw new UnimplementedError();
   }
 }
 
@@ -402,7 +402,7 @@
   }
 
   @override
-  ApplyChangesStatus applyChanges(ChangeSet changeSet) {
+  void applyChanges(ChangeSet changeSet) {
     fail("Unexpected invocation of applyChanges");
     return null;
   }
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 1f6f81a..b003089 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -119,6 +119,22 @@
     verify([source]);
   }
 
+  void test_canBeNullAfterNullAware_false_null() {
+    Source source = addSource(r'''
+m(x) {
+  x?.a.hashCode;
+  x?.a.runtimeType;
+  x?.a.toString();
+  x?.b().hashCode;
+  x?.b().runtimeType;
+  x?.b().toString();
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_canBeNullAfterNullAware_methodInvocation() {
     Source source = addSource(r'''
 m(x) {
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index d9720af..006ef07 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -322,70 +322,8 @@
 
 @reflectiveTest
 class LibraryImportScopeTest extends ResolverTestCase {
-  void test_conflictingImports() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore();
-    String typeNameA = "A";
-    String typeNameB = "B";
-    String typeNameC = "C";
-    ClassElement typeA = ElementFactory.classElement2(typeNameA);
-    ClassElement typeB1 = ElementFactory.classElement2(typeNameB);
-    ClassElement typeB2 = ElementFactory.classElement2(typeNameB);
-    ClassElement typeC = ElementFactory.classElement2(typeNameC);
-    LibraryElement importedLibrary1 = createTestLibrary(context, "imported1");
-    (importedLibrary1.definingCompilationUnit as CompilationUnitElementImpl)
-        .types = <ClassElement>[typeA, typeB1];
-    ImportElementImpl import1 =
-        ElementFactory.importFor(importedLibrary1, null);
-    LibraryElement importedLibrary2 = createTestLibrary(context, "imported2");
-    (importedLibrary2.definingCompilationUnit as CompilationUnitElementImpl)
-        .types = <ClassElement>[typeB2, typeC];
-    ImportElementImpl import2 =
-        ElementFactory.importFor(importedLibrary2, null);
-    LibraryElementImpl importingLibrary =
-        createTestLibrary(context, "importing");
-    importingLibrary.imports = <ImportElement>[import1, import2];
-    {
-      GatheringErrorListener errorListener = new GatheringErrorListener();
-      Scope scope = new LibraryImportScope(importingLibrary, errorListener);
-      expect(scope.lookup(AstFactory.identifier3(typeNameA), importingLibrary),
-          typeA);
-      errorListener.assertNoErrors();
-      expect(scope.lookup(AstFactory.identifier3(typeNameC), importingLibrary),
-          typeC);
-      errorListener.assertNoErrors();
-      Element element =
-          scope.lookup(AstFactory.identifier3(typeNameB), importingLibrary);
-      errorListener.assertErrorsWithCodes([StaticWarningCode.AMBIGUOUS_IMPORT]);
-      EngineTestCase.assertInstanceOf((obj) => obj is MultiplyDefinedElement,
-          MultiplyDefinedElement, element);
-      List<Element> conflictingElements =
-          (element as MultiplyDefinedElement).conflictingElements;
-      expect(conflictingElements, hasLength(2));
-      if (identical(conflictingElements[0], typeB1)) {
-        expect(conflictingElements[1], same(typeB2));
-      } else if (identical(conflictingElements[0], typeB2)) {
-        expect(conflictingElements[1], same(typeB1));
-      } else {
-        expect(conflictingElements[0], same(typeB1));
-      }
-    }
-    {
-      GatheringErrorListener errorListener = new GatheringErrorListener();
-      Scope scope = new LibraryImportScope(importingLibrary, errorListener);
-      Identifier identifier = AstFactory.identifier3(typeNameB);
-      AstFactory.methodDeclaration(null, AstFactory.typeName3(identifier), null,
-          null, AstFactory.identifier3("foo"), null);
-      Element element = scope.lookup(identifier, importingLibrary);
-      errorListener.assertErrorsWithCodes([StaticWarningCode.AMBIGUOUS_IMPORT]);
-      EngineTestCase.assertInstanceOf((obj) => obj is MultiplyDefinedElement,
-          MultiplyDefinedElement, element);
-    }
-  }
-
   void test_creation_empty() {
-    LibraryElement definingLibrary = createDefaultTestLibrary();
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    new LibraryImportScope(definingLibrary, errorListener);
+    new LibraryImportScope(createDefaultTestLibrary());
   }
 
   void test_creation_nonEmpty() {
@@ -401,68 +339,12 @@
     ImportElementImpl importElement = new ImportElementImpl(0);
     importElement.importedLibrary = importedLibrary;
     definingLibrary.imports = <ImportElement>[importElement];
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    Scope scope = new LibraryImportScope(definingLibrary, errorListener);
+    Scope scope = new LibraryImportScope(definingLibrary);
     expect(
         scope.lookup(AstFactory.identifier3(importedTypeName), definingLibrary),
         importedType);
   }
 
-  void test_getErrorListener() {
-    LibraryElement definingLibrary = createDefaultTestLibrary();
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    LibraryImportScope scope =
-        new LibraryImportScope(definingLibrary, errorListener);
-    expect(scope.errorListener, errorListener);
-  }
-
-  void test_nonConflictingImports_fromSdk() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore();
-    String typeName = "List";
-    ClassElement type = ElementFactory.classElement2(typeName);
-    LibraryElement importedLibrary = createTestLibrary(context, "lib");
-    (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
-        .types = <ClassElement>[type];
-    ImportElementImpl importCore = ElementFactory.importFor(
-        context.getLibraryElement(context.sourceFactory.forUri("dart:core")),
-        null);
-    ImportElementImpl importLib =
-        ElementFactory.importFor(importedLibrary, null);
-    LibraryElementImpl importingLibrary =
-        createTestLibrary(context, "importing");
-    importingLibrary.imports = <ImportElement>[importCore, importLib];
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    Scope scope = new LibraryImportScope(importingLibrary, errorListener);
-    expect(
-        scope.lookup(AstFactory.identifier3(typeName), importingLibrary), type);
-    errorListener
-        .assertErrorsWithCodes([StaticWarningCode.CONFLICTING_DART_IMPORT]);
-  }
-
-  void test_nonConflictingImports_sameElement() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore();
-    String typeNameA = "A";
-    String typeNameB = "B";
-    ClassElement typeA = ElementFactory.classElement2(typeNameA);
-    ClassElement typeB = ElementFactory.classElement2(typeNameB);
-    LibraryElement importedLibrary = createTestLibrary(context, "imported");
-    (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
-        .types = <ClassElement>[typeA, typeB];
-    ImportElementImpl import1 = ElementFactory.importFor(importedLibrary, null);
-    ImportElementImpl import2 = ElementFactory.importFor(importedLibrary, null);
-    LibraryElementImpl importingLibrary =
-        createTestLibrary(context, "importing");
-    importingLibrary.imports = <ImportElement>[import1, import2];
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    Scope scope = new LibraryImportScope(importingLibrary, errorListener);
-    expect(scope.lookup(AstFactory.identifier3(typeNameA), importingLibrary),
-        typeA);
-    errorListener.assertNoErrors();
-    expect(scope.lookup(AstFactory.identifier3(typeNameB), importingLibrary),
-        typeB);
-    errorListener.assertNoErrors();
-  }
-
   void test_prefixedAndNonPrefixed() {
     AnalysisContext context = AnalysisContextFactory.contextWithCore();
     String typeName = "C";
@@ -487,15 +369,12 @@
       prefixedImport,
       nonPrefixedImport
     ];
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    Scope scope = new LibraryImportScope(importingLibrary, errorListener);
+    Scope scope = new LibraryImportScope(importingLibrary);
     Element prefixedElement = scope.lookup(
         AstFactory.identifier5(prefixName, typeName), importingLibrary);
-    errorListener.assertNoErrors();
     expect(prefixedElement, same(prefixedType));
     Element nonPrefixedElement =
         scope.lookup(AstFactory.identifier3(typeName), importingLibrary);
-    errorListener.assertNoErrors();
     expect(nonPrefixedElement, same(nonPrefixedType));
   }
 }
@@ -503,9 +382,7 @@
 @reflectiveTest
 class LibraryScopeTest extends ResolverTestCase {
   void test_creation_empty() {
-    LibraryElement definingLibrary = createDefaultTestLibrary();
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    new LibraryScope(definingLibrary, errorListener);
+    new LibraryScope(createDefaultTestLibrary());
   }
 
   void test_creation_nonEmpty() {
@@ -521,19 +398,11 @@
     ImportElementImpl importElement = new ImportElementImpl(0);
     importElement.importedLibrary = importedLibrary;
     definingLibrary.imports = <ImportElement>[importElement];
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    Scope scope = new LibraryScope(definingLibrary, errorListener);
+    Scope scope = new LibraryScope(definingLibrary);
     expect(
         scope.lookup(AstFactory.identifier3(importedTypeName), definingLibrary),
         importedType);
   }
-
-  void test_getErrorListener() {
-    LibraryElement definingLibrary = createDefaultTestLibrary();
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    LibraryScope scope = new LibraryScope(definingLibrary, errorListener);
-    expect(scope.errorListener, errorListener);
-  }
 }
 
 @reflectiveTest
@@ -596,8 +465,7 @@
 @reflectiveTest
 class ScopeTest extends ResolverTestCase {
   void test_define_duplicate() {
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ScopeTest_TestScope scope = new ScopeTest_TestScope(errorListener);
+    ScopeTest_TestScope scope = new ScopeTest_TestScope();
     SimpleIdentifier identifier = AstFactory.identifier3("v1");
     VariableElement element1 = ElementFactory.localVariableElement(identifier);
     VariableElement element2 = ElementFactory.localVariableElement(identifier);
@@ -607,21 +475,13 @@
   }
 
   void test_define_normal() {
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ScopeTest_TestScope scope = new ScopeTest_TestScope(errorListener);
+    ScopeTest_TestScope scope = new ScopeTest_TestScope();
     VariableElement element1 =
         ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
     VariableElement element2 =
         ElementFactory.localVariableElement(AstFactory.identifier3("v2"));
     scope.define(element1);
     scope.define(element2);
-    errorListener.assertNoErrors();
-  }
-
-  void test_getErrorListener() {
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ScopeTest_TestScope scope = new ScopeTest_TestScope(errorListener);
-    expect(scope.errorListener, errorListener);
   }
 
   void test_isPrivateName_nonPrivate() {
@@ -637,12 +497,11 @@
  * A non-abstract subclass that can be used for testing purposes.
  */
 class ScopeTest_TestScope extends Scope {
-  /**
-   * The listener that is to be informed when an error is encountered.
-   */
-  final AnalysisErrorListener errorListener;
+  ScopeTest_TestScope();
 
-  ScopeTest_TestScope(this.errorListener);
+  @deprecated
+  @override
+  AnalysisErrorListener get errorListener => null;
 
   @override
   Element internalLookup(Identifier identifier, String name,
@@ -1126,24 +985,18 @@
 class TypeOverrideManagerTest extends EngineTestCase {
   void test_exitScope_noScopes() {
     TypeOverrideManager manager = new TypeOverrideManager();
-    try {
+    expect(() {
       manager.exitScope();
-      fail("Expected IllegalStateException");
-    } on IllegalStateException {
-      // Expected
-    }
+    }, throwsStateError);
   }
 
   void test_exitScope_oneScope() {
     TypeOverrideManager manager = new TypeOverrideManager();
     manager.enterScope();
     manager.exitScope();
-    try {
+    expect(() {
       manager.exitScope();
-      fail("Expected IllegalStateException");
-    } on IllegalStateException {
-      // Expected
-    }
+    }, throwsStateError);
   }
 
   void test_exitScope_twoScopes() {
@@ -1152,12 +1005,9 @@
     manager.exitScope();
     manager.enterScope();
     manager.exitScope();
-    try {
+    expect(() {
       manager.exitScope();
-      fail("Expected IllegalStateException");
-    } on IllegalStateException {
-      // Expected
-    }
+    }, throwsStateError);
   }
 
   void test_getType_enclosedOverride() {
@@ -2929,7 +2779,7 @@
     element.definingCompilationUnit =
         new CompilationUnitElementImpl("lib.dart");
     _typeProvider = new TestTypeProvider();
-    libraryScope = new LibraryScope(element, _listener);
+    libraryScope = new LibraryScope(element);
     _visitor = new TypeResolverVisitor(
         element, librarySource, _typeProvider, _listener,
         nameScope: libraryScope);
diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
index c63cc85..10b0b97 100644
--- a/pkg/analyzer/test/generated/resolver_test_case.dart
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -8,13 +8,13 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
@@ -473,15 +473,12 @@
   }
 
   /**
-   * Cache the source file content in the source factory but don't add the source to the analysis
-   * context. The file path should be absolute.
-   *
-   * @param filePath the path of the file being cached
-   * @param contents the contents to be returned by the content provider for the specified file
-   * @return the source object representing the cached file
+   * Cache the [contents] for the file at the given [filePath] but don't add the
+   * source to the analysis context. The file path must be absolute.
    */
   Source cacheSource(String filePath, String contents) {
-    Source source = new FileBasedSource(FileUtilities2.createFile(filePath));
+    Source source =
+        PhysicalResourceProvider.INSTANCE.getFile(filePath).createSource();
     analysisContext2.setContents(source, contents);
     return source;
   }
@@ -518,10 +515,10 @@
    * Create a source object representing a file with the given [fileName] and
    * give it an empty content. Return the source that was created.
    */
-  FileBasedSource createNamedSource(String fileName) {
-    FileBasedSource source =
-        new FileBasedSource(FileUtilities2.createFile(fileName));
-    analysisContext2.setContents(source, "");
+  Source createNamedSource(String fileName) {
+    Source source =
+        PhysicalResourceProvider.INSTANCE.getFile(fileName).createSource();
+    analysisContext2.setContents(source, '');
     return source;
   }
 
@@ -535,8 +532,8 @@
   LibraryElementImpl createTestLibrary(
       AnalysisContext context, String libraryName,
       [List<String> typeNames]) {
-    String fileName = "$libraryName.dart";
-    FileBasedSource definingCompilationUnitSource = createNamedSource(fileName);
+    String fileName = "/test/$libraryName.dart";
+    Source definingCompilationUnitSource = createNamedSource(fileName);
     List<CompilationUnitElement> sourcedCompilationUnits;
     if (typeNames == null) {
       sourcedCompilationUnits = CompilationUnitElement.EMPTY_LIST;
@@ -593,7 +590,7 @@
       // "fail_*" tests. However, an assertion failure is success for the
       // purpose of "fail_*" tests, so without catching them here "fail_*" tests
       // can succeed by failing for the wrong reason.
-      throw new JavaException("Unexexpected assertion failure: $exception");
+      throw new StateError("Unexpected assertion failure: $exception");
     }
   }
 
@@ -764,6 +761,7 @@
       }
       fail('Wrong element type: ${element.runtimeType}');
     }
+
     SimpleIdentifier identifier = findIdentifier(name);
     // Element is either ExecutableElement or ParameterElement.
     Element element = identifier.staticElement;
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index 77f9d74..c8eb8f2 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -239,14 +239,13 @@
 
   void test_fromEncoding_invalidUri() {
     SourceFactory factory = new SourceFactory([]);
-    expect(() => factory.fromEncoding("<:&%>"),
-        throwsA(new isInstanceOf<IllegalArgumentException>()));
+    expect(() => factory.fromEncoding("<:&%>"), throwsArgumentError);
   }
 
   void test_fromEncoding_noResolver() {
     SourceFactory factory = new SourceFactory([]);
     expect(() => factory.fromEncoding("foo:/does/not/exist.dart"),
-        throwsA(new isInstanceOf<IllegalArgumentException>()));
+        throwsArgumentError);
   }
 
   void test_fromEncoding_valid() {
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 0cb986d..2fc3fc5 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/static_type_analyzer.dart';
@@ -1427,12 +1426,7 @@
    */
   DartType _analyze4(
       Expression node, InterfaceType thisType, bool useStaticType) {
-    try {
-      _analyzer.thisType = thisType;
-    } catch (exception) {
-      throw new IllegalArgumentException(
-          "Could not set type of 'this'", exception);
-    }
+    _analyzer.thisType = thisType;
     node.accept(_analyzer);
     if (useStaticType) {
       return node.staticType;
@@ -1552,14 +1546,9 @@
     _typeProvider = new TestTypeProvider(context);
     _visitor = new ResolverVisitor(
         definingLibrary, source, _typeProvider, _listener,
-        nameScope: new LibraryScope(definingLibrary, _listener));
+        nameScope: new LibraryScope(definingLibrary));
     _visitor.overrideManager.enterScope();
-    try {
-      return _visitor.typeAnalyzer;
-    } catch (exception) {
-      throw new IllegalArgumentException(
-          "Could not create analyzer", exception);
-    }
+    return _visitor.typeAnalyzer;
   }
 
   DartType _flatten(DartType type) => type.flattenFutures(_typeSystem);
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 93da8f0..c113838 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -12,7 +12,6 @@
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:plugin/manager.dart';
@@ -129,7 +128,7 @@
       AstNode root, String code, String prefix, Predicate<AstNode> predicate) {
     int offset = code.indexOf(prefix);
     if (offset == -1) {
-      throw new IllegalArgumentException("Not found '$prefix'.");
+      throw new ArgumentError("Not found '$prefix'.");
     }
     AstNode node = new NodeLocator(offset).searchWithin(root);
     return node.getAncestor(predicate);
@@ -142,7 +141,7 @@
       AstNode root, String code, String prefix) {
     int offset = code.indexOf(prefix);
     if (offset == -1) {
-      throw new IllegalArgumentException("Not found '$prefix'.");
+      throw new ArgumentError("Not found '$prefix'.");
     }
     return new NodeLocator(offset).searchWithin(root);
   }
@@ -460,23 +459,17 @@
       Source source = error.source;
       LineInfo lineInfo = _lineInfoMap[source];
       buffer.writeln();
+      String sourceName = source == null ? '' : source.shortName;
       if (lineInfo == null) {
         int offset = error.offset;
-        StringUtils.printf(buffer, "  %s %s (%d..%d)", [
-          source == null ? "" : source.shortName,
-          error.errorCode,
-          offset,
-          offset + error.length
-        ]);
+        buffer.write('  $sourceName ${error.errorCode} '
+            '($offset..${offset + error.length})');
       } else {
         LineInfo_Location location = lineInfo.getLocation(error.offset);
-        StringUtils.printf(buffer, "  %s %s (%d, %d/%d)", [
-          source == null ? "" : source.shortName,
-          error.errorCode,
-          location.lineNumber,
-          location.columnNumber,
-          error.length
-        ]);
+        int lineNumber = location.lineNumber;
+        int columnNumber = location.columnNumber;
+        buffer.write('  $sourceName ${error.errorCode} '
+            '($lineNumber, $columnNumber/${error.length})');
       }
     }
     buffer.writeln();
@@ -487,25 +480,17 @@
       Source source = error.source;
       LineInfo lineInfo = _lineInfoMap[source];
       buffer.writeln();
+      String sourceName = source == null ? '' : source.shortName;
       if (lineInfo == null) {
         int offset = error.offset;
-        StringUtils.printf(buffer, "  %s %s (%d..%d): %s", [
-          source == null ? "" : source.shortName,
-          error.errorCode,
-          offset,
-          offset + error.length,
-          error.message
-        ]);
+        buffer.write('  $sourceName ${error.errorCode} '
+            '($offset..${offset + error.length}): ${error.message}');
       } else {
         LineInfo_Location location = lineInfo.getLocation(error.offset);
-        StringUtils.printf(buffer, "  %s %s (%d, %d/%d): %s", [
-          source == null ? "" : source.shortName,
-          error.errorCode,
-          location.lineNumber,
-          location.columnNumber,
-          error.length,
-          error.message
-        ]);
+        int lineNumber = location.lineNumber;
+        int columnNumber = location.columnNumber;
+        buffer.write('  $sourceName ${error.errorCode} '
+            '($lineNumber, $columnNumber/${error.length}): ${error.message}');
       }
     }
     fail(buffer.toString());
@@ -603,7 +588,7 @@
   Uri get uri => new Uri.file(_name);
 
   UriKind get uriKind {
-    throw new UnsupportedOperationException();
+    throw new UnsupportedError('uriKind');
   }
 
   bool operator ==(Object other) {
@@ -615,11 +600,11 @@
 
   bool exists() => exists2;
   void getContentsToReceiver(Source_ContentReceiver receiver) {
-    throw new UnsupportedOperationException();
+    throw new UnsupportedError('getContentsToReceiver');
   }
 
   Source resolve(String uri) {
-    throw new UnsupportedOperationException();
+    throw new UnsupportedError('resolve');
   }
 
   void setContents(String value) {
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index ed78f6d..3dc407d 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -1455,12 +1455,7 @@
   void test_findCycleContaining_null() {
     DirectedGraph<DirectedGraphTest_Node> graph =
         new DirectedGraph<DirectedGraphTest_Node>();
-    try {
-      graph.findCycleContaining(null);
-      fail("Expected IllegalArgumentException");
-    } on IllegalArgumentException {
-      // Expected
-    }
+    expect(() => graph.findCycleContaining(null), throwsArgumentError);
   }
 
   void test_findCycleContaining_singleton() {
@@ -2524,21 +2519,15 @@
   }
 
   void test_creation_empty() {
-    try {
+    expect(() {
       new LineInfo(<int>[]);
-      fail("Expected IllegalArgumentException");
-    } on IllegalArgumentException {
-      // Expected
-    }
+    }, throwsArgumentError);
   }
 
   void test_creation_null() {
-    try {
+    expect(() {
       new LineInfo(null);
-      fail("Expected IllegalArgumentException");
-    } on IllegalArgumentException {
-      // Expected
-    }
+    }, throwsArgumentError);
   }
 
   void test_firstLine() {
@@ -2899,24 +2888,11 @@
     Map<String, String> map = new HashMap<String, String>();
     MultipleMapIterator<String, String> iterator = _iterator(<Map>[map]);
     expect(iterator.moveNext(), isFalse);
-    try {
-      iterator.key;
-      fail("Expected NoSuchElementException");
-    } on NoSuchElementException {
-      // Expected
-    }
-    try {
-      iterator.value;
-      fail("Expected NoSuchElementException");
-    } on NoSuchElementException {
-      // Expected
-    }
-    try {
-      iterator.value = "x";
-      fail("Expected NoSuchElementException");
-    } on NoSuchElementException {
-      // Expected
-    }
+    expect(() => iterator.key, throwsStateError);
+    expect(() => iterator.value, throwsStateError);
+    expect(() {
+      iterator.value = 'x';
+    }, throwsStateError);
   }
 
   void test_singleMap_multiple() {
@@ -3904,24 +3880,11 @@
     SingleMapIterator<String, String> iterator =
         new SingleMapIterator<String, String>(map);
     expect(iterator.moveNext(), isFalse);
-    try {
-      iterator.key;
-      fail("Expected NoSuchElementException");
-    } on NoSuchElementException {
-      // Expected
-    }
-    try {
-      iterator.value;
-      fail("Expected NoSuchElementException");
-    } on NoSuchElementException {
-      // Expected
-    }
-    try {
-      iterator.value = "x";
-      fail("Expected NoSuchElementException");
-    } on NoSuchElementException {
-      // Expected
-    }
+    expect(() => iterator.key, throwsStateError);
+    expect(() => iterator.value, throwsStateError);
+    expect(() {
+      iterator.value = 'x';
+    }, throwsStateError);
     expect(iterator.moveNext(), isFalse);
   }
 
@@ -4214,12 +4177,9 @@
   }
 
   void test_printListOfQuotedNames_empty() {
-    try {
+    expect(() {
       StringUtilities.printListOfQuotedNames(new List<String>(0));
-      fail("Expected IllegalArgumentException");
-    } on IllegalArgumentException {
-      // Expected
-    }
+    }, throwsArgumentError);
   }
 
   void test_printListOfQuotedNames_five() {
@@ -4230,21 +4190,15 @@
   }
 
   void test_printListOfQuotedNames_null() {
-    try {
+    expect(() {
       StringUtilities.printListOfQuotedNames(null);
-      fail("Expected IllegalArgumentException");
-    } on IllegalArgumentException {
-      // Expected
-    }
+    }, throwsArgumentError);
   }
 
   void test_printListOfQuotedNames_one() {
-    try {
+    expect(() {
       StringUtilities.printListOfQuotedNames(<String>["a"]);
-      fail("Expected IllegalArgumentException");
-    } on IllegalArgumentException {
-      // Expected
-    }
+    }, throwsArgumentError);
   }
 
   void test_printListOfQuotedNames_three() {
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 5a91ee3..7f86af5 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -398,8 +398,7 @@
     // it is already overridden in the content cache.
     ChangeSet changeSet = new ChangeSet();
     changeSet.changedSource(source);
-    ApplyChangesStatus changesStatus = context.applyChanges(changeSet);
-    expect(changesStatus.hasChanges, isFalse);
+    context.applyChanges(changeSet);
     expect(context.sourcesNeedingProcessing, hasLength(0));
   }
 
diff --git a/pkg/analyzer/test/src/dart/constant/value_test.dart b/pkg/analyzer/test/src/dart/constant/value_test.dart
index 60151a0..1323714 100644
--- a/pkg/analyzer/test/src/dart/constant/value_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/value_test.dart
@@ -18,8 +18,12 @@
   defineReflectiveTests(DartObjectImplTest);
 }
 
+const Matcher isEvaluationException = const isInstanceOf<EvaluationException>();
+
 const int LONG_MAX_VALUE = 0x7fffffffffffffff;
 
+const Matcher throwsEvaluationException = const Throws(isEvaluationException);
+
 @reflectiveTest
 class DartObjectImplTest extends EngineTestCase {
   TypeProvider _typeProvider = new TestTypeProvider();
@@ -961,18 +965,16 @@
   }
 
   void test_logicalAnd_false_null() {
-    try {
+    expect(() {
       _assertLogicalAnd(_boolValue(false), _boolValue(false), _nullValue());
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_false_string() {
-    try {
+    expect(() {
       _assertLogicalAnd(
           _boolValue(false), _boolValue(false), _stringValue("false"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_false_true() {
@@ -980,33 +982,29 @@
   }
 
   void test_logicalAnd_null_false() {
-    try {
+    expect(() {
       _assertLogicalAnd(_boolValue(false), _nullValue(), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_null_true() {
-    try {
+    expect(() {
       _assertLogicalAnd(_boolValue(false), _nullValue(), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_string_false() {
-    try {
+    expect(() {
       _assertLogicalAnd(
           _boolValue(false), _stringValue("true"), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_string_true() {
-    try {
+    expect(() {
       _assertLogicalAnd(
           _boolValue(false), _stringValue("false"), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_true_false() {
@@ -1018,11 +1016,10 @@
   }
 
   void test_logicalAnd_true_string() {
-    try {
+    expect(() {
       _assertLogicalAnd(
           _boolValue(false), _boolValue(true), _stringValue("true"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalAnd_true_true() {
@@ -1038,10 +1035,9 @@
   }
 
   void test_logicalNot_string() {
-    try {
+    expect(() {
       _assertLogicalNot(_boolValue(true), _stringValue(null));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalNot_true() {
@@ -1061,11 +1057,10 @@
   }
 
   void test_logicalOr_false_string() {
-    try {
+    expect(() {
       _assertLogicalOr(
           _boolValue(false), _boolValue(false), _stringValue("false"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_false_true() {
@@ -1073,33 +1068,29 @@
   }
 
   void test_logicalOr_null_false() {
-    try {
+    expect(() {
       _assertLogicalOr(_boolValue(false), _nullValue(), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_null_true() {
-    try {
+    expect(() {
       _assertLogicalOr(_boolValue(true), _nullValue(), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_string_false() {
-    try {
+    expect(() {
       _assertLogicalOr(
           _boolValue(false), _stringValue("true"), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_string_true() {
-    try {
+    expect(() {
       _assertLogicalOr(
           _boolValue(true), _stringValue("false"), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_true_false() {
@@ -1107,18 +1098,16 @@
   }
 
   void test_logicalOr_true_null() {
-    try {
+    expect(() {
       _assertLogicalOr(_boolValue(true), _boolValue(true), _nullValue());
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_true_string() {
-    try {
+    expect(() {
       _assertLogicalOr(
           _boolValue(true), _boolValue(true), _stringValue("true"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_logicalOr_true_true() {
@@ -1407,10 +1396,9 @@
   }
 
   void test_stringLength_int() {
-    try {
+    expect(() {
       _assertStringLength(_intValue(null), _intValue(0));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
+    }, throwsEvaluationException);
   }
 
   void test_stringLength_knownString() {
@@ -1481,10 +1469,9 @@
   void _assertAdd(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.add(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.add(_typeProvider, right);
       expect(result, isNotNull);
@@ -1500,10 +1487,9 @@
   void _assertBitAnd(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.bitAnd(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.bitAnd(_typeProvider, right);
       expect(result, isNotNull);
@@ -1517,10 +1503,9 @@
    */
   void _assertBitNot(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
-      try {
+      expect(() {
         operand.bitNot(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = operand.bitNot(_typeProvider);
       expect(result, isNotNull);
@@ -1536,10 +1521,9 @@
   void _assertBitOr(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.bitOr(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.bitOr(_typeProvider, right);
       expect(result, isNotNull);
@@ -1555,10 +1539,9 @@
   void _assertBitXor(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.bitXor(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.bitXor(_typeProvider, right);
       expect(result, isNotNull);
@@ -1574,10 +1557,9 @@
   void _assertConcatenate(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.concatenate(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.concatenate(_typeProvider, right);
       expect(result, isNotNull);
@@ -1593,10 +1575,9 @@
   void _assertDivide(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.divide(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.divide(_typeProvider, right);
       expect(result, isNotNull);
@@ -1612,10 +1593,9 @@
   void _assertEqualEqual(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.equalEqual(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.equalEqual(_typeProvider, right);
       expect(result, isNotNull);
@@ -1631,10 +1611,9 @@
   void _assertGreaterThan(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.greaterThan(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.greaterThan(_typeProvider, right);
       expect(result, isNotNull);
@@ -1650,10 +1629,9 @@
   void _assertGreaterThanOrEqual(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.greaterThanOrEqual(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.greaterThanOrEqual(_typeProvider, right);
       expect(result, isNotNull);
@@ -1684,10 +1662,9 @@
   void _assertIntegerDivide(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.integerDivide(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.integerDivide(_typeProvider, right);
       expect(result, isNotNull);
@@ -1703,10 +1680,9 @@
   void _assertLessThan(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.lessThan(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.lessThan(_typeProvider, right);
       expect(result, isNotNull);
@@ -1722,10 +1698,9 @@
   void _assertLessThanOrEqual(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.lessThanOrEqual(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.lessThanOrEqual(_typeProvider, right);
       expect(result, isNotNull);
@@ -1741,10 +1716,9 @@
   void _assertLogicalAnd(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.logicalAnd(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.logicalAnd(_typeProvider, right);
       expect(result, isNotNull);
@@ -1758,10 +1732,9 @@
    */
   void _assertLogicalNot(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
-      try {
+      expect(() {
         operand.logicalNot(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = operand.logicalNot(_typeProvider);
       expect(result, isNotNull);
@@ -1777,10 +1750,9 @@
   void _assertLogicalOr(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.logicalOr(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.logicalOr(_typeProvider, right);
       expect(result, isNotNull);
@@ -1796,10 +1768,9 @@
   void _assertMinus(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.minus(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.minus(_typeProvider, right);
       expect(result, isNotNull);
@@ -1813,10 +1784,9 @@
    */
   void _assertNegated(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
-      try {
+      expect(() {
         operand.negated(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = operand.negated(_typeProvider);
       expect(result, isNotNull);
@@ -1832,10 +1802,9 @@
   void _assertNotEqual(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.notEqual(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.notEqual(_typeProvider, right);
       expect(result, isNotNull);
@@ -1849,10 +1818,9 @@
    */
   void _assertPerformToString(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
-      try {
+      expect(() {
         operand.performToString(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = operand.performToString(_typeProvider);
       expect(result, isNotNull);
@@ -1868,10 +1836,9 @@
   void _assertRemainder(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.remainder(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.remainder(_typeProvider, right);
       expect(result, isNotNull);
@@ -1887,10 +1854,9 @@
   void _assertShiftLeft(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.shiftLeft(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.shiftLeft(_typeProvider, right);
       expect(result, isNotNull);
@@ -1906,10 +1872,9 @@
   void _assertShiftRight(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.shiftRight(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.shiftRight(_typeProvider, right);
       expect(result, isNotNull);
@@ -1923,10 +1888,9 @@
    */
   void _assertStringLength(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
-      try {
+      expect(() {
         operand.stringLength(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = operand.stringLength(_typeProvider);
       expect(result, isNotNull);
@@ -1942,10 +1906,9 @@
   void _assertTimes(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
-      try {
+      expect(() {
         left.times(_typeProvider, right);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
+      }, throwsEvaluationException);
     } else {
       DartObjectImpl result = left.times(_typeProvider, right);
       expect(result, isNotNull);
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index ed56338..6bc35ef 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -13,7 +13,6 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisOptionsImpl;
-import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
@@ -3942,10 +3941,10 @@
     LibraryElement library = ElementFactory.library(context, "foo");
     context.setContents(library.definingCompilationUnit.source, "sdfsdff");
     // Assert that we are not up to date if the target has an old time stamp.
-    expect(library.isUpToDate(0), isFalse);
+    expect(library.isUpToDate(-1), isFalse);
     // Assert that we are up to date with a target modification time in the
     // future.
-    expect(library.isUpToDate(JavaSystem.currentTimeMillis() + 1000), isTrue);
+    expect(library.isUpToDate(1 << 33), isTrue);
   }
 
   void test_setImports() {
@@ -4076,8 +4075,11 @@
 @reflectiveTest
 class MultiplyDefinedElementImplTest extends EngineTestCase {
   void test_fromElements_conflicting() {
-    Element firstElement = ElementFactory.localVariableElement2("xx");
-    Element secondElement = ElementFactory.localVariableElement2("yy");
+    TopLevelVariableElement firstElement =
+        ElementFactory.topLevelVariableElement2('xx');
+    TopLevelVariableElement secondElement =
+        ElementFactory.topLevelVariableElement2('yy');
+    _addToLibrary([firstElement, secondElement]);
     Element result = MultiplyDefinedElementImpl.fromElements(
         null, firstElement, secondElement);
     EngineTestCase.assertInstanceOf(
@@ -4086,15 +4088,19 @@
         (result as MultiplyDefinedElement).conflictingElements;
     expect(elements, hasLength(2));
     for (int i = 0; i < elements.length; i++) {
-      EngineTestCase.assertInstanceOf((obj) => obj is LocalVariableElement,
-          LocalVariableElement, elements[i]);
+      EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableElement,
+          TopLevelVariableElement, elements[i]);
     }
   }
 
   void test_fromElements_multiple() {
-    Element firstElement = ElementFactory.localVariableElement2("xx");
-    Element secondElement = ElementFactory.localVariableElement2("yy");
-    Element thirdElement = ElementFactory.localVariableElement2("zz");
+    TopLevelVariableElement firstElement =
+        ElementFactory.topLevelVariableElement2('xx');
+    TopLevelVariableElement secondElement =
+        ElementFactory.topLevelVariableElement2('yy');
+    TopLevelVariableElement thirdElement =
+        ElementFactory.topLevelVariableElement2('zz');
+    _addToLibrary([firstElement, secondElement, thirdElement]);
     Element result = MultiplyDefinedElementImpl.fromElements(
         null,
         MultiplyDefinedElementImpl.fromElements(
@@ -4106,16 +4112,26 @@
         (result as MultiplyDefinedElement).conflictingElements;
     expect(elements, hasLength(3));
     for (int i = 0; i < elements.length; i++) {
-      EngineTestCase.assertInstanceOf((obj) => obj is LocalVariableElement,
-          LocalVariableElement, elements[i]);
+      EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableElement,
+          TopLevelVariableElement, elements[i]);
     }
   }
 
   void test_fromElements_nonConflicting() {
-    Element element = ElementFactory.localVariableElement2("xx");
+    TopLevelVariableElement element =
+        ElementFactory.topLevelVariableElement2('xx');
+    _addToLibrary([element]);
     expect(MultiplyDefinedElementImpl.fromElements(null, element, element),
         same(element));
   }
+
+  void _addToLibrary(List<TopLevelVariableElement> variables) {
+    CompilationUnitElementImpl compilationUnit =
+        ElementFactory.compilationUnit('lib.dart');
+    LibraryElementImpl library = ElementFactory.library(null, 'lib');
+    library.definingCompilationUnit = compilationUnit;
+    compilationUnit.topLevelVariables = variables;
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/summary/pub_summary_test.dart b/pkg/analyzer/test/src/summary/pub_summary_test.dart
index 58d5f09..4ecf074 100644
--- a/pkg/analyzer/test/src/summary/pub_summary_test.dart
+++ b/pkg/analyzer/test/src/summary/pub_summary_test.dart
@@ -260,6 +260,47 @@
     }
   }
 
+  test_getLinkedBundles_cached_inconsistent_majorVersion() async {
+    String pathA = '$CACHE/aaa';
+    resourceProvider.newFile(
+        '$pathA/lib/a.dart',
+        '''
+class A {}
+int a;
+''');
+    // Configure packages resolution.
+    Folder libFolderA = resourceProvider.newFolder('$pathA/lib');
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      sdkResolver,
+      resourceResolver,
+      new PackageMapUriResolver(resourceProvider, {
+        'aaa': [libFolderA],
+      })
+    ]);
+
+    // Session 1.
+    // Create the linked bundle and cache it in a file.
+    {
+      // Ensure unlinked bundles.
+      manager.getUnlinkedBundles(context);
+      await manager.onUnlinkedComplete;
+
+      // Now we should be able to get the linked bundle.
+      List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+      expect(linkedPackages, hasLength(1));
+    }
+
+    // Session 2.
+    // Recreate manager with a different major version.
+    // It cannot use the previously cache linked bundle.
+    // The reason is that we cannot use the cached unlinked bundle.
+    {
+      _createManager(majorVersion: 12345);
+      List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+      expect(linkedPackages, isEmpty);
+    }
+  }
+
   test_getLinkedBundles_hasCycle() async {
     resourceProvider.newFile(
         '$CACHE/aaa/lib/a.dart',
@@ -924,6 +965,56 @@
     _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
   }
 
+  test_getUnlinkedBundles_inconsistent_majorVersion() async {
+    // Create package files.
+    resourceProvider.newFile(
+        '$CACHE/aaa/lib/a.dart',
+        '''
+class A {}
+''');
+
+    // Configure packages resolution.
+    Folder libFolder = resourceProvider.newFolder('$CACHE/aaa/lib');
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      sdkResolver,
+      resourceResolver,
+      new PackageMapUriResolver(resourceProvider, {
+        'aaa': [libFolder],
+      })
+    ]);
+
+    /**
+     * Verify that the [manager] has exactly one cache bundle `aaa`.
+     */
+    void _assertSingleBundle() {
+      Map<PubPackage, PackageBundle> bundles =
+          manager.getUnlinkedBundles(context);
+      expect(bundles, hasLength(1));
+      PackageBundle bundle = _getBundleByPackageName(bundles, 'aaa');
+      expect(bundle.unlinkedUnitUris, ['package:aaa/a.dart']);
+    }
+
+    // Compute the bundle using a non-default major version.
+    _createManager(majorVersion: 12345);
+    manager.getUnlinkedBundles(context);
+    await manager.onUnlinkedComplete;
+    _assertSingleBundle();
+
+    // Recompute when using the default major version.
+    _createManager();
+    expect(manager.getUnlinkedBundles(context), isEmpty);
+
+    // Wait for the bundle to be computed.
+    await manager.onUnlinkedComplete;
+    _assertSingleBundle();
+    _assertFileExists(libFolder.parent, PubSummaryManager.UNLINKED_NAME);
+    _assertFileExists(libFolder.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
+
+    // Can read from the file again.
+    _createManager();
+    _assertSingleBundle();
+  }
+
   test_getUnlinkedBundles_notPubCache_dontCreate() async {
     String aaaPath = '/Users/user/projects/aaa';
     // Create package files.
@@ -1048,6 +1139,47 @@
     _assertFileExists(libFolderB.parent, PubSummaryManager.UNLINKED_SPEC_NAME);
   }
 
+  test_getUnlinkedBundles_notPubCache_useExisting_inconsistent() async {
+    String aaaPath = '/Users/user/projects/aaa';
+    // Create package files.
+    resourceProvider.newFile(
+        '$aaaPath/lib/a.dart',
+        '''
+class A {}
+''');
+
+    // Compute the bundles.
+    Folder libFolderA = resourceProvider.getFolder('$aaaPath/lib');
+    await new PubSummaryManager(resourceProvider, '_.temp')
+        .computeUnlinkedForFolder('aaa', libFolderA);
+
+    // Configure packages resolution.
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      sdkResolver,
+      resourceResolver,
+      new PackageMapUriResolver(resourceProvider, {
+        'aaa': [libFolderA],
+      })
+    ]);
+
+    // Request already available unlinked bundles.
+    expect(manager.getUnlinkedBundles(context), hasLength(1));
+
+    // Update a Dart file.
+    // So, the cached bundle cannot be reused.
+    resourceProvider.updateFile(
+        '$aaaPath/lib/a.dart',
+        '''
+class A2 {}
+''');
+    _createManager();
+    expect(manager.getUnlinkedBundles(context), isEmpty);
+
+    // ...and because it is not in the pub cache, it will not be recomputed.
+    await manager.onUnlinkedComplete;
+    expect(manager.getUnlinkedBundles(context), isEmpty);
+  }
+
   test_getUnlinkedBundles_nullPackageMap() async {
     context.sourceFactory =
         new SourceFactory(<UriResolver>[sdkResolver, resourceResolver]);
@@ -1125,8 +1257,10 @@
     fail('Cannot find variable $variableName in $linkedPackage');
   }
 
-  void _createManager() {
-    manager = new PubSummaryManager(resourceProvider, '_.temp');
+  void _createManager(
+      {int majorVersion: PackageBundleAssembler.currentMajorVersion}) {
+    manager = new PubSummaryManager(resourceProvider, '_.temp',
+        majorVersion: majorVersion);
   }
 
   LinkedPubPackage _getLinkedPackage(
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index aecebc6..2cdb1bf 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -586,14 +586,14 @@
   /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
   /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
   /*error:INVALID_FIELD_OVERRIDE*/var f3;
-  /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic f4;
+  /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic f4;
 }
 
 class Child2 implements Base {
   /*error:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
   /*error:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
   var f3;
-  /*error:INVALID_METHOD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic f4;
+  /*error:INVALID_METHOD_OVERRIDE*/dynamic f4;
 }
 ''');
   }
@@ -671,7 +671,7 @@
   /*error:INVALID_FIELD_OVERRIDE*/void set f1(A value) {}
   /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
   /*error:INVALID_FIELD_OVERRIDE*/void set f3(value) {}
-  /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
+  /*error:INVALID_FIELD_OVERRIDE*/void set f4(dynamic value) {}
   /*error:INVALID_FIELD_OVERRIDE*/set f5(B value) {}
 }
 
@@ -685,7 +685,7 @@
   void set f1(A value) {}
   /*error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
   void set f3(value) {}
-  /*error:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
+  void set f4(dynamic value) {}
   set f5(B value) {}
 }
 ''');
@@ -3186,15 +3186,15 @@
 class G extends F {
   /*error:INVALID_METHOD_OVERRIDE*/void set f(ToVoid<int> x) {}
   void set g(ToVoid<dynamic> x) {}
-  void set h(int x) {}
-  /*error:INVALID_METHOD_OVERRIDE*/void set i(dynamic x) {}
+  /*error:INVALID_METHOD_OVERRIDE*/void set h(int x) {}
+  void set i(dynamic x) {}
 }
 
 class H implements F {
   /*error:INVALID_METHOD_OVERRIDE*/void set f(ToVoid<int> x) {}
   void set g(ToVoid<dynamic> x) {}
-  void set h(int x) {}
-  /*error:INVALID_METHOD_OVERRIDE*/void set i(dynamic x) {}
+  /*error:INVALID_METHOD_OVERRIDE*/void set h(int x) {}
+  void set i(dynamic x) {}
 }
  ''');
   }
@@ -3235,7 +3235,7 @@
   void set f1(A value) {}
   /*error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
   void set f3(value) {}
-  /*error:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
+  void set f4(dynamic value) {}
   set f5(B value) {}
 }
 ''');
diff --git a/pkg/analyzer/tool/task_dependency_graph/generate.dart b/pkg/analyzer/tool/task_dependency_graph/generate.dart
index 0caa453..db88145 100644
--- a/pkg/analyzer/tool/task_dependency_graph/generate.dart
+++ b/pkg/analyzer/tool/task_dependency_graph/generate.dart
@@ -25,7 +25,9 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/codegen/tools.dart';
+import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index ddcd776..538692a 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -98,6 +98,10 @@
     return null;
   }
 
+  /// Returns `true` if [element] is a default implementation of `noSuchMethod`
+  /// used by the target.
+  bool isDefaultNoSuchMethod(MethodElement element);
+
   /// Returns the default superclass for the given [element] in this target.
   ClassElement defaultSuperclass(ClassElement element);
 
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 114bdca..b4e586a 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -222,11 +222,23 @@
     return outputUnitTo.imports.containsAll(outputUnitFrom.imports);
   }
 
+  // TODO(het): use a union-find to canonicalize output units
+  OutputUnit _getCanonicalUnit(OutputUnit outputUnit) {
+    OutputUnit representative = allOutputUnits.lookup(outputUnit);
+    if (representative == null) {
+      representative = outputUnit;
+      allOutputUnits.add(representative);
+    }
+    return representative;
+  }
+
   void registerConstantDeferredUse(
       DeferredConstantValue constant, PrefixElement prefix) {
     OutputUnit outputUnit = new OutputUnit();
     outputUnit.imports.add(new _DeclaredDeferredImport(prefix.deferredImport));
-    _constantToOutputUnit[constant] = outputUnit;
+
+    // Check to see if there is already a canonical output unit registered.
+    _constantToOutputUnit[constant] = _getCanonicalUnit(outputUnit);
   }
 
   /// Answers whether [element] is explicitly deferred when referred to from
@@ -679,6 +691,11 @@
               Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder =
                   new Map<ConstantValue, OutputUnit>();
 
+              // Add all constants that may have been registered during
+              // resolution with [registerConstantDeferredUse].
+              constantToOutputUnitBuilder.addAll(_constantToOutputUnit);
+              _constantToOutputUnit.clear();
+
               // Reverse the mappings. For each element record an OutputUnit
               // collecting all deferred imports mapped to this element. Same
               // for constants.
@@ -721,21 +738,11 @@
               // to, and canonicalize them.
               elementToOutputUnitBuilder
                   .forEach((Element element, OutputUnit outputUnit) {
-                OutputUnit representative = allOutputUnits.lookup(outputUnit);
-                if (representative == null) {
-                  representative = outputUnit;
-                  allOutputUnits.add(representative);
-                }
-                _elementToOutputUnit[element] = representative;
+                _elementToOutputUnit[element] = _getCanonicalUnit(outputUnit);
               });
               constantToOutputUnitBuilder
                   .forEach((ConstantValue constant, OutputUnit outputUnit) {
-                OutputUnit representative = allOutputUnits.lookup(outputUnit);
-                if (representative == null) {
-                  representative = outputUnit;
-                  allOutputUnits.add(representative);
-                }
-                _constantToOutputUnit[constant] = representative;
+                _constantToOutputUnit[constant] = _getCanonicalUnit(outputUnit);
               });
 
               // Generate a unique name for each OutputUnit.
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index d5314b0..2afb849 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -115,8 +115,7 @@
   }
 
   FieldInfo visitFieldElement(FieldElement element, _) {
-    TypeMask inferredType =
-        compiler.globalInference.getGuaranteedTypeOfElement(element);
+    TypeMask inferredType = compiler.globalInference.results.typeOf(element);
     // If a field has an empty inferred type it is never used.
     if (inferredType == null || inferredType.isEmpty) return null;
 
@@ -257,7 +256,7 @@
       signature.forEachParameter((parameter) {
         parameters.add(new ParameterInfo(
             parameter.name,
-            '${compiler.globalInference.getGuaranteedTypeOfElement(parameter)}',
+            '${compiler.globalInference.results.typeOf(parameter)}',
             '${parameter.node.type}'));
       });
     }
@@ -270,7 +269,7 @@
       returnType = '${element.type.returnType}';
     }
     String inferredReturnType =
-        '${compiler.globalInference.getGuaranteedReturnTypeOfElement(element)}';
+        '${compiler.globalInference.results.returnTypeOf(element)}';
     String sideEffects = '${compiler.world.getSideEffectsOfElement(element)}';
 
     int inlinedCount = compiler.dumpInfoTask.inlineCount[element];
@@ -321,6 +320,7 @@
       // emitter is used it will fail here.
       JavaScriptBackend backend = compiler.backend;
       full.Emitter emitter = backend.emitter.emitter;
+      assert(outputUnit.name != null || outputUnit.isMainOutput);
       OutputUnitInfo info = new OutputUnitInfo(
           outputUnit.name, emitter.outputBuffers[outputUnit].length);
       info.imports.addAll(outputUnit.imports
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 06b9670..24c8771 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -309,22 +309,12 @@
 
       void processClass(ClassElement superclass) {
         if (_processedClasses.contains(superclass)) return;
-        // TODO(johnniwinther): Re-insert this invariant when unittests don't
-        // fail. There is already a similar invariant on the members.
-        /*if (!isResolutionQueue) {
-          assert(invariant(superclass,
-              superclass.isClosure ||
-              compiler.enqueuer.resolution.isClassProcessed(superclass),
-              message: "Class $superclass has not been "
-                       "processed in resolution."));
-        }*/
 
         _processedClasses.add(superclass);
         recentClasses.add(superclass);
         superclass.ensureResolved(resolution);
         superclass.implementation.forEachMember(processInstantiatedClassMember);
-        if (isResolutionQueue &&
-            !compiler.serialization.isDeserialized(superclass)) {
+        if (!compiler.serialization.isDeserialized(superclass)) {
           compiler.resolver.checkClass(superclass);
         }
         // We only tell the backend once that [superclass] was instantiated, so
@@ -352,7 +342,7 @@
 
   void logEnqueueReflectiveAction(action, [msg = ""]) {
     if (TRACE_MIRROR_ENQUEUING) {
-      print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg");
+      print("MIRROR_ENQUEUE (R): $action $msg");
     }
   }
 
@@ -384,7 +374,6 @@
       if (element.isTypedef) {
         TypedefElement typedef = element;
         typedef.ensureResolved(resolution);
-        compiler.world.allTypedefs.add(element);
       } else if (Elements.isStaticOrTopLevel(element)) {
         registerStaticUse(new StaticUse.foreignUse(element.declaration));
       } else if (element.isInstanceMember) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 2308e41..42c6913 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -1381,7 +1381,7 @@
     return inferrer.types.getInferredTypeOf(element).type;
   }
 
-  TypeMask getTypeOfNode(Element owner, ast.Node node) {
+  TypeMask getTypeForNewList(Element owner, ast.Node node) {
     if (compiler.disableTypeInference) return _dynamicType;
     return inferrer.types.allocatedLists[node].type;
   }
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index d155aaa..e813fe9 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -635,6 +635,11 @@
   JavaScriptConstantCompiler get constants {
     return constantCompilerTask.jsConstantCompiler;
   }
+  
+  @override
+  bool isDefaultNoSuchMethod(MethodElement element) {
+    return noSuchMethodRegistry.isDefaultNoSuchMethodImplementation(element);
+  }
 
   MethodElement resolveExternalFunction(MethodElement element) {
     if (isForeign(element)) {
@@ -1101,7 +1106,7 @@
         type.isFunctionType ? coreTypes.functionType : type;
     if (type is InterfaceType) {
       registry.registerInstantiation(instantiatedType);
-      if (!type.treatAsRaw && classNeedsRti(type.element)) {
+      if (classNeedsRtiField(type.element)) {
         registry.registerStaticUse(new StaticUse.staticInvoke(
             // TODO(johnniwinther): Find the right [CallStructure].
             helpers.setRuntimeTypeInfo,
@@ -1470,8 +1475,14 @@
   }
 
   bool classNeedsRti(ClassElement cls) {
-    return rti.classesNeedingRti.contains(cls.declaration) ||
-        compiler.enabledRuntimeType;
+    if (compiler.enabledRuntimeType) return true;
+    return rti.classesNeedingRti.contains(cls.declaration);
+  }
+
+  bool classNeedsRtiField(ClassElement cls) {
+    if (cls.rawType.typeArguments.isEmpty) return false;
+    if (compiler.enabledRuntimeType) return true;
+    return rti.classesNeedingRti.contains(cls.declaration);
   }
 
   bool isComplexNoSuchMethod(FunctionElement element) =>
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index c922d4d..e30ef91 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -251,10 +251,14 @@
           "Compiler and ${className} disagree on number of fields.");
     }
 
+    if (backend.classNeedsRtiField(classElement)) {
+      arguments.add(_reifiedTypeArguments(constant.type));
+    }
+
     jsAst.Expression constructor =
         backend.emitter.constructorAccess(classElement);
     jsAst.Expression value = new jsAst.New(constructor, arguments);
-    return maybeAddTypeArguments(constant.type, value);
+    return value;
   }
 
   JavaScriptBackend get backend => compiler.backend;
@@ -307,6 +311,9 @@
     element.forEachInstanceField((_, FieldElement field) {
       fields.add(constantReferenceGenerator(constant.fields[field]));
     }, includeSuperAndInjectedMembers: true);
+    if (backend.classNeedsRtiField(constant.type.element)) {
+      fields.add(_reifiedTypeArguments(constant.type));
+    }
     jsAst.New instantiation = new jsAst.New(constructor, fields);
     return maybeAddTypeArguments(constant.type, instantiation);
   }
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index d95c529..80f241f 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -6,9 +6,10 @@
 
 import 'dart:collection' show Queue;
 
+import '../common/backend_api.dart' show Backend;
 import '../common/codegen.dart' show CodegenWorkItem;
+import '../common/registry.dart' show Registry;
 import '../common/names.dart' show Identifiers;
-import '../common/resolution.dart' show Resolution;
 import '../common/work.dart' show WorkItem;
 import '../common.dart';
 import '../compiler.dart' show Compiler;
@@ -30,6 +31,7 @@
 import '../enqueue.dart';
 import '../js/js.dart' as js;
 import '../native/native.dart' as native;
+import '../options.dart';
 import '../types/types.dart' show TypeMaskStrategy;
 import '../universe/selector.dart' show Selector;
 import '../universe/universe.dart';
@@ -38,11 +40,13 @@
 import '../universe/world_impact.dart'
     show ImpactUseCase, WorldImpact, WorldImpactVisitor;
 import '../util/util.dart' show Setlet;
+import '../world.dart';
 
 /// [Enqueuer] which is specific to code generation.
 class CodegenEnqueuer implements Enqueuer {
   final String name;
-  final Compiler compiler; // TODO(ahe): Remove this dependency.
+  @deprecated
+  final Compiler _compiler; // TODO(ahe): Remove this dependency.
   final EnqueuerStrategy strategy;
   final Map<String, Set<Element>> instanceMembersByName =
       new Map<String, Set<Element>>();
@@ -69,25 +73,28 @@
         newlyEnqueuedElements = compiler.cacheStrategy.newSet(),
         newlySeenSelectors = compiler.cacheStrategy.newSet(),
         this.name = 'codegen enqueuer',
-        this.compiler = compiler {
+        this._compiler = compiler {
     impactVisitor = new _EnqueuerImpactVisitor(this);
   }
 
-  // TODO(johnniwinther): Move this to [ResolutionEnqueuer].
-  Resolution get resolution => compiler.resolution;
+  Backend get backend => _compiler.backend;
+
+  CompilerOptions get options => _compiler.options;
+
+  Registry get globalDependencies => _compiler.globalDependencies;
+
+  Registry get mirrorDependencies => _compiler.mirrorDependencies;
+
+  ClassWorld get _world => _compiler.world;
 
   bool get queueIsEmpty => queue.isEmpty;
 
   /// Returns [:true:] if this enqueuer is the resolution enqueuer.
   bool get isResolutionQueue => false;
 
-  QueueFilter get filter => compiler.enqueuerFilter;
+  QueueFilter get filter => _compiler.enqueuerFilter;
 
-  DiagnosticReporter get reporter => compiler.reporter;
-
-  bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
-
-  Iterable<ClassElement> get processedClasses => _processedClasses;
+  DiagnosticReporter get reporter => _compiler.reporter;
 
   /**
    * Documentation wanted -- johnniwinther
@@ -96,30 +103,50 @@
    */
   void addToWorkList(Element element) {
     assert(invariant(element, element.isDeclaration));
-    if (internalAddToWorkList(element) && compiler.options.dumpInfo) {
+    // Don't generate code for foreign elements.
+    if (backend.isForeign(element)) return;
+
+    // Codegen inlines field initializers. It only needs to generate
+    // code for checked setters.
+    if (element.isField && element.isInstanceMember) {
+      if (!options.enableTypeAssertions ||
+          element.enclosingElement.isClosure) {
+        return;
+      }
+    }
+
+    if (options.hasIncrementalSupport && !isProcessed(element)) {
+      newlyEnqueuedElements.add(element);
+    }
+
+    if (queueIsClosed) {
+      throw new SpannableAssertionFailure(
+          element, "Codegen work list is closed. Trying to add $element");
+    }
+    queue.add(new CodegenWorkItem(_compiler, element));
+    if (options.dumpInfo) {
       // TODO(sigmund): add other missing dependencies (internals, selectors
       // enqueued after allocations), also enable only for the codegen enqueuer.
-      compiler.dumpInfoTask
-          .registerDependency(compiler.currentElement, element);
+      _compiler.dumpInfoTask
+          .registerDependency(_compiler.currentElement, element);
     }
   }
 
   /// Apply the [worldImpact] of processing [element] to this enqueuer.
   void applyImpact(Element element, WorldImpact worldImpact) {
-    compiler.impactStrategy
+    _compiler.impactStrategy
         .visitImpact(element, worldImpact, impactVisitor, impactUse);
   }
 
   void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) {
     task.measure(() {
       ClassElement cls = type.element;
-      cls.ensureResolved(resolution);
-      bool isNative = compiler.backend.isNative(cls);
+      bool isNative = backend.isNative(cls);
       universe.registerTypeInstantiation(type,
           isNative: isNative,
           byMirrors: mirrorUsage, onImplemented: (ClassElement cls) {
-        compiler.backend
-            .registerImplementedClass(cls, this, compiler.globalDependencies);
+        backend
+            .registerImplementedClass(cls, this, globalDependencies);
       });
       // TODO(johnniwinther): Share this reasoning with [Universe].
       if (!cls.isAbstract || isNative || mirrorUsage) {
@@ -150,14 +177,14 @@
       // its metadata parsed and analyzed.
       // Note: this assumes that there are no non-native fields on native
       // classes, which may not be the case when a native class is subclassed.
-      if (compiler.backend.isNative(cls)) {
-        compiler.world.registerUsedElement(member);
-        if (universe.hasInvokedGetter(member, compiler.world) ||
-            universe.hasInvocation(member, compiler.world)) {
+      if (backend.isNative(cls)) {
+        _compiler.world.registerUsedElement(member);
+        if (universe.hasInvokedGetter(member, _world) ||
+            universe.hasInvocation(member, _world)) {
           addToWorkList(member);
           return;
         }
-        if (universe.hasInvokedSetter(member, compiler.world)) {
+        if (universe.hasInvokedSetter(member, _world)) {
           addToWorkList(member);
           return;
         }
@@ -172,7 +199,6 @@
       }
     } else if (member.isFunction) {
       FunctionElement function = member;
-      function.computeType(resolution);
       if (function.name == Identifiers.noSuchMethod_) {
         registerNoSuchMethod(function);
       }
@@ -181,7 +207,7 @@
       }
       // If there is a property access with the same name as a method we
       // need to emit the method.
-      if (universe.hasInvokedGetter(function, compiler.world)) {
+      if (universe.hasInvokedGetter(function, _world)) {
         registerClosurizedMember(function);
         addToWorkList(function);
         return;
@@ -191,27 +217,25 @@
       instanceFunctionsByName
           .putIfAbsent(memberName, () => new Set<Element>())
           .add(member);
-      if (universe.hasInvocation(function, compiler.world)) {
+      if (universe.hasInvocation(function, _world)) {
         addToWorkList(function);
         return;
       }
     } else if (member.isGetter) {
       FunctionElement getter = member;
-      getter.computeType(resolution);
-      if (universe.hasInvokedGetter(getter, compiler.world)) {
+      if (universe.hasInvokedGetter(getter, _world)) {
         addToWorkList(getter);
         return;
       }
       // We don't know what selectors the returned closure accepts. If
       // the set contains any selector we have to assume that it matches.
-      if (universe.hasInvocation(getter, compiler.world)) {
+      if (universe.hasInvocation(getter, _world)) {
         addToWorkList(getter);
         return;
       }
     } else if (member.isSetter) {
       FunctionElement setter = member;
-      setter.computeType(resolution);
-      if (universe.hasInvokedSetter(setter, compiler.world)) {
+      if (universe.hasInvokedSetter(setter, _world)) {
         addToWorkList(setter);
         return;
       }
@@ -229,35 +253,26 @@
   void processInstantiatedClass(ClassElement cls) {
     task.measure(() {
       if (_processedClasses.contains(cls)) return;
-      // The class must be resolved to compute the set of all
-      // supertypes.
-      cls.ensureResolved(resolution);
 
       void processClass(ClassElement superclass) {
         if (_processedClasses.contains(superclass)) return;
         // TODO(johnniwinther): Re-insert this invariant when unittests don't
         // fail. There is already a similar invariant on the members.
-        /*if (!isResolutionQueue) {
-          assert(invariant(superclass,
+        /*assert(invariant(superclass,
               superclass.isClosure ||
-              compiler.enqueuer.resolution.isClassProcessed(superclass),
+              _compiler.enqueuer.resolution.isClassProcessed(superclass),
               message: "Class $superclass has not been "
                        "processed in resolution."));
-        }*/
+        */
 
         _processedClasses.add(superclass);
         recentClasses.add(superclass);
-        superclass.ensureResolved(resolution);
         superclass.implementation.forEachMember(processInstantiatedClassMember);
-        if (isResolutionQueue &&
-            !compiler.serialization.isDeserialized(superclass)) {
-          compiler.resolver.checkClass(superclass);
-        }
         // We only tell the backend once that [superclass] was instantiated, so
         // any additional dependencies must be treated as global
         // dependencies.
-        compiler.backend.registerInstantiatedClass(
-            superclass, this, compiler.globalDependencies);
+        backend.registerInstantiatedClass(
+            superclass, this, globalDependencies);
       }
 
       ClassElement superclass = cls;
@@ -278,7 +293,7 @@
 
   void logEnqueueReflectiveAction(action, [msg = ""]) {
     if (TRACE_MIRROR_ENQUEUING) {
-      print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg");
+      print("MIRROR_ENQUEUE (C): $action $msg");
     }
   }
 
@@ -292,8 +307,8 @@
         includedEnclosing: enclosingWasIncluded)) {
       logEnqueueReflectiveAction(ctor);
       ClassElement cls = ctor.declaration.enclosingClass;
-      compiler.backend.registerInstantiatedType(
-          cls.rawType, this, compiler.mirrorDependencies,
+      backend.registerInstantiatedType(
+          cls.rawType, this, mirrorDependencies,
           mirrorUsage: true);
       registerStaticUse(new StaticUse.foreignUse(ctor.declaration));
     }
@@ -308,9 +323,7 @@
         includedEnclosing: enclosingWasIncluded)) {
       logEnqueueReflectiveAction(element);
       if (element.isTypedef) {
-        TypedefElement typedef = element;
-        typedef.ensureResolved(resolution);
-        compiler.world.allTypedefs.add(element);
+        // Do nothing.
       } else if (Elements.isStaticOrTopLevel(element)) {
         registerStaticUse(new StaticUse.foreignUse(element.declaration));
       } else if (element.isInstanceMember) {
@@ -343,9 +356,8 @@
     if (includeClass) {
       logEnqueueReflectiveAction(cls, "register");
       ClassElement decl = cls.declaration;
-      decl.ensureResolved(resolution);
-      compiler.backend.registerInstantiatedType(
-          decl.rawType, this, compiler.mirrorDependencies,
+      backend.registerInstantiatedType(
+          decl.rawType, this, mirrorDependencies,
           mirrorUsage: true);
     }
     // If the class is never instantiated, we know nothing of it can possibly
@@ -371,13 +383,12 @@
   /// inheritance.
   void enqueueReflectiveSpecialClasses() {
     Iterable<ClassElement> classes =
-        compiler.backend.classesRequiredForReflection;
+        backend.classesRequiredForReflection;
     for (ClassElement cls in classes) {
-      if (compiler.backend.referencedFromMirrorSystem(cls)) {
+      if (backend.referencedFromMirrorSystem(cls)) {
         logEnqueueReflectiveAction(cls);
-        cls.ensureResolved(resolution);
-        compiler.backend.registerInstantiatedType(
-            cls.rawType, this, compiler.mirrorDependencies,
+        backend.registerInstantiatedType(
+            cls.rawType, this, mirrorDependencies,
             mirrorUsage: true);
       }
     }
@@ -412,7 +423,7 @@
       // enqueued.
       recents = _processedClasses.toSet();
       reporter.log('Enqueuing everything');
-      for (LibraryElement lib in compiler.libraryLoader.libraries) {
+      for (LibraryElement lib in _compiler.libraryLoader.libraries) {
         enqueueReflectiveElementsInLibrary(lib, recents);
       }
       enqueueReflectiveSpecialClasses();
@@ -474,7 +485,7 @@
     Selector selector = dynamicUse.selector;
     String methodName = selector.name;
     processInstanceMembers(methodName, (Element member) {
-      if (dynamicUse.appliesUnnamed(member, compiler.world)) {
+      if (dynamicUse.appliesUnnamed(member, _world)) {
         if (member.isFunction && selector.isGetter) {
           registerClosurizedMember(member);
         }
@@ -485,7 +496,7 @@
     });
     if (selector.isGetter) {
       processInstanceFunctions(methodName, (Element member) {
-        if (dynamicUse.appliesUnnamed(member, compiler.world)) {
+        if (dynamicUse.appliesUnnamed(member, _world)) {
           registerClosurizedMember(member);
           return true;
         }
@@ -508,11 +519,11 @@
     assert(invariant(element, element.isDeclaration,
         message: "Element ${element} is not the declaration."));
     universe.registerStaticUse(staticUse);
-    compiler.backend.registerStaticUse(element, this);
+    backend.registerStaticUse(element, this);
     bool addElement = true;
     switch (staticUse.kind) {
       case StaticUseKind.STATIC_TEAR_OFF:
-        compiler.backend.registerGetOfStaticFunction(this);
+        backend.registerGetOfStaticFunction(this);
         break;
       case StaticUseKind.FIELD_GET:
       case StaticUseKind.FIELD_SET:
@@ -546,7 +557,7 @@
         _registerIsCheck(type);
         break;
       case TypeUseKind.CHECKED_MODE_CHECK:
-        if (compiler.options.enableTypeAssertions) {
+        if (options.enableTypeAssertions) {
           _registerIsCheck(type);
         }
         break;
@@ -556,7 +567,7 @@
   }
 
   void _registerIsCheck(DartType type) {
-    type = universe.registerIsCheck(type, compiler);
+    type = universe.registerIsCheck(type, _compiler);
     // Even in checked mode, type annotations for return type and argument
     // types do not imply type checks, so there should never be a check
     // against the type variable of a typedef.
@@ -564,18 +575,18 @@
   }
 
   void registerCallMethodWithFreeTypeVariables(Element element) {
-    compiler.backend.registerCallMethodWithFreeTypeVariables(
-        element, this, compiler.globalDependencies);
+    backend.registerCallMethodWithFreeTypeVariables(
+        element, this, globalDependencies);
     universe.callMethodsWithFreeTypeVariables.add(element);
   }
 
   void registerClosurizedMember(TypedElement element) {
     assert(element.isInstanceMember);
-    if (element.computeType(resolution).containsTypeVariables) {
-      compiler.backend.registerClosureWithFreeTypeVariables(
-          element, this, compiler.globalDependencies);
+    if (element.type.containsTypeVariables) {
+      backend.registerClosureWithFreeTypeVariables(
+          element, this, globalDependencies);
     }
-    compiler.backend.registerBoundClosure(this);
+    backend.registerBoundClosure(this);
     universe.closurizedMembers.add(element);
   }
 
@@ -598,7 +609,7 @@
   /// returned, [onQueueEmpty] will be called once the queue is empty again (or
   /// still empty) and [recentClasses] will be a superset of the current value.
   bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
-    return compiler.backend.onQueueEmpty(this, recentClasses);
+    return backend.onQueueEmpty(this, recentClasses);
   }
 
   void logSummary(log(message)) {
@@ -609,7 +620,7 @@
   String toString() => 'Enqueuer($name)';
 
   void _forgetElement(Element element) {
-    universe.forgetElement(element, compiler);
+    universe.forgetElement(element, _compiler);
     _processedClasses.remove(element);
     instanceMembersByName[element.name]?.remove(element);
     instanceFunctionsByName[element.name]?.remove(element);
@@ -641,42 +652,12 @@
    */
   bool shouldIncludeElementDueToMirrors(Element element,
       {bool includedEnclosing}) {
-    return compiler.backend.isAccessibleByReflection(element);
-  }
-
-  /**
-   * Adds [element] to the work list if it has not already been processed.
-   *
-   * Returns [true] if the element was actually added to the queue.
-   */
-  bool internalAddToWorkList(Element element) {
-    // Don't generate code for foreign elements.
-    if (compiler.backend.isForeign(element)) return false;
-
-    // Codegen inlines field initializers. It only needs to generate
-    // code for checked setters.
-    if (element.isField && element.isInstanceMember) {
-      if (!compiler.options.enableTypeAssertions ||
-          element.enclosingElement.isClosure) {
-        return false;
-      }
-    }
-
-    if (compiler.options.hasIncrementalSupport && !isProcessed(element)) {
-      newlyEnqueuedElements.add(element);
-    }
-
-    if (queueIsClosed) {
-      throw new SpannableAssertionFailure(
-          element, "Codegen work list is closed. Trying to add $element");
-    }
-    queue.add(new CodegenWorkItem(compiler, element));
-    return true;
+    return backend.isAccessibleByReflection(element);
   }
 
   void registerNoSuchMethod(Element element) {
-    if (!enabledNoSuchMethod && compiler.backend.enabledNoSuchMethod) {
-      compiler.backend.enableNoSuchMethod(this);
+    if (!enabledNoSuchMethod && backend.enabledNoSuchMethod) {
+      backend.enableNoSuchMethod(this);
       enabledNoSuchMethod = true;
     }
   }
@@ -698,7 +679,7 @@
   }
 
   void handleUnseenSelector(DynamicUse dynamicUse) {
-    if (compiler.options.hasIncrementalSupport) {
+    if (options.hasIncrementalSupport) {
       newlySeenSelectors.add(dynamicUse);
     }
     _handleUnseenSelector(dynamicUse);
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index bef06b2..39abf47 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -125,7 +125,7 @@
   }
 
   _subcategorizeOther(FunctionElement element) {
-    if (_compiler.globalInference.throwsAlways(element)) {
+    if (_compiler.globalInference.results.throwsAlways(element)) {
       complexNoReturnImpls.add(element);
     } else {
       complexReturningImpls.add(element);
@@ -150,7 +150,7 @@
       notApplicableImpls.add(element);
       return NsmCategory.NOT_APPLICABLE;
     }
-    if (_isDefaultNoSuchMethodImplementation(element)) {
+    if (isDefaultNoSuchMethodImplementation(element)) {
       defaultImpls.add(element);
       return NsmCategory.DEFAULT;
     } else if (_hasForwardingSyntax(element)) {
@@ -186,7 +186,7 @@
     }
   }
 
-  bool _isDefaultNoSuchMethodImplementation(FunctionElement element) {
+  bool isDefaultNoSuchMethodImplementation(FunctionElement element) {
     ClassElement classElement = element.enclosingClass;
     return classElement == _compiler.coreClasses.objectClass ||
         classElement == _backend.helpers.jsInterceptorClass ||
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index 447710d..d07c36f 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -11,8 +11,8 @@
 
   ClassStubGenerator(this.compiler, this.namer, this.backend);
 
-  jsAst.Expression generateClassConstructor(
-      ClassElement classElement, Iterable<jsAst.Name> fields) {
+  jsAst.Expression generateClassConstructor(ClassElement classElement,
+      Iterable<jsAst.Name> fields, bool hasRtiField) {
     // TODO(sra): Implement placeholders in VariableDeclaration position:
     //
     //     String constructorName = namer.getNameOfClass(classElement);
@@ -20,9 +20,18 @@
     //        [ constructorName, fields,
     //            fields.map(
     //                (name) => js('this.# = #', [name, name]))]));
-    return js('function(#) { #; this.#();}', [
+    var typeParameters = const <jsAst.Parameter>[];
+    var typeInits = const <jsAst.Expression>[];
+    if (hasRtiField) {
+      String parameterName = r'$ti';
+      typeParameters = parameterName;
+      typeInits = js('this.# = #', [namer.rtiFieldName, parameterName]);
+    }
+    return js('function(#, #) { #; #; this.#();}', [
       fields,
+      typeParameters,
       fields.map((name) => js('this.# = #', [name, name])),
+      typeInits,
       namer.deferredAction
     ]);
   }
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
index 0538a2d..5a6fb44 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
@@ -35,6 +35,9 @@
     builder.superName = superName;
     emitConstructorsForCSP(cls);
     emitFields(cls, builder);
+    if (cls.hasRtiField) {
+      builder.addField(namer.rtiFieldName);
+    }
     emitCheckedClassSetters(cls, builder);
     emitClassGettersSettersForCSP(cls, builder);
     emitInstanceMembers(cls, builder);
@@ -69,8 +72,8 @@
 
     ClassElement classElement = cls.element;
 
-    jsAst.Expression constructorAst =
-        _stubGenerator.generateClassConstructor(classElement, fieldNames);
+    jsAst.Expression constructorAst = _stubGenerator.generateClassConstructor(
+        classElement, fieldNames, cls.hasRtiField);
 
     jsAst.Name constructorName = namer.className(classElement);
     OutputUnit outputUnit =
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index 14e0b75..53f12e3 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
@@ -625,6 +625,9 @@
     // or RTI. In either case we don't need its fields.
     if (cls.isDirectlyInstantiated && !cls.isNative) {
       fieldNames = cls.fields.map((Field field) => field.name).toList();
+      if (cls.hasRtiField) {
+        fieldNames.add(namer.rtiFieldName);
+      }
     }
     js.Name name = cls.name;
 
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index a9a6d26..62070c2 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -229,6 +229,7 @@
   /// noSuchMethod stubs in the special case that the class is Object.
   final List<StubMethod> noSuchMethodStubs;
   final List<Field> staticFieldsForReflection;
+  final bool hasRtiField; // Per-instance runtime type information pseudo-field.
   final bool onlyForRti;
   final bool isDirectlyInstantiated;
   final bool isNative;
@@ -262,7 +263,8 @@
       this.checkedSetters,
       this.isChecks,
       this.functionTypeIndex,
-      {this.onlyForRti,
+      {this.hasRtiField,
+      this.onlyForRti,
       this.isDirectlyInstantiated,
       this.isNative}) {
     assert(onlyForRti != null);
@@ -297,7 +299,8 @@
       List<StubMethod> checkedSetters,
       List<StubMethod> isChecks,
       js.Expression functionTypeIndex,
-      {bool onlyForRti,
+      {bool hasRtiField,
+      bool onlyForRti,
       bool isDirectlyInstantiated})
       : super(
             element,
@@ -312,6 +315,7 @@
             checkedSetters,
             isChecks,
             functionTypeIndex,
+            hasRtiField: hasRtiField,
             onlyForRti: onlyForRti,
             isDirectlyInstantiated: isDirectlyInstantiated,
             isNative: false);
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index efec052..a3dc79f 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -499,12 +499,14 @@
     return new Class(
         element, name, null, [], instanceFields, [], [], [], [], [], [], null,
         isDirectlyInstantiated: true,
+        hasRtiField: backend.classNeedsRtiField(element),
         onlyForRti: false,
         isNative: backend.isNative(element));
   }
 
   Class _buildClass(ClassElement element) {
     bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
+    bool hasRtiField = backend.classNeedsRtiField(element);
     if (backend.isJsInterop(element)) {
       // TODO(jacobr): check whether the class has any active static fields
       // if it does not we can suppress it completely.
@@ -635,6 +637,7 @@
           isChecks,
           typeTests.functionTypeIndex,
           isDirectlyInstantiated: isInstantiated,
+          hasRtiField: hasRtiField,
           onlyForRti: onlyForRti);
     } else {
       result = new Class(
@@ -651,6 +654,7 @@
           isChecks,
           typeTests.functionTypeIndex,
           isDirectlyInstantiated: isInstantiated,
+          hasRtiField: hasRtiField,
           onlyForRti: onlyForRti,
           isNative: backend.isNative(element));
     }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 12245c7..222b1c6 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -629,19 +629,29 @@
   ///
   /// The constructor is statically built.
   js.Expression emitConstructor(Class cls) {
-    List<js.Name> fieldNames = const <js.Name>[];
-
+    js.Name name = cls.name;
     // If the class is not directly instantiated we only need it for inheritance
     // or RTI. In either case we don't need its fields.
-    if (cls.isDirectlyInstantiated && !cls.isNative) {
-      fieldNames = cls.fields.map((Field field) => field.name).toList();
+    if (cls.isNative || !cls.isDirectlyInstantiated) {
+      return js.js('function #() { }', name);
     }
-    js.Name name = cls.name;
+
+    List<js.Name> fieldNames =
+        cls.fields.map((Field field) => field.name).toList();
+    if (cls.hasRtiField) {
+      fieldNames.add(namer.rtiFieldName);
+    }
 
     Iterable<js.Name> assignments = fieldNames.map((js.Name field) {
       return js.js("this.#field = #field", {"field": field});
     });
 
+    // TODO(sra): Cache 'this' in a one-character local for 4 or more uses of
+    // 'this'. i.e. "var _=this;_.a=a;_.b=b;..."
+
+    // TODO(sra): Separate field and field initializer parameter names so the
+    // latter may be fully minified.
+
     return js.js('function #(#) { # }', [name, fieldNames, assignments]);
   }
 
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index ba50456..3039130 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -69,7 +69,8 @@
     computeMembers(null, null);
     if (!cls.isAbstract) {
       Member member = classMembers[Names.noSuchMethod_];
-      if (member != null && !member.declarer.isObject) {
+      if (member != null &&
+          !resolution.target.isDefaultNoSuchMethod(member.element)) {
         return;
       }
       // Check for unimplemented members on concrete classes that neither have
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 042ac75..9f54ceb 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -377,6 +377,7 @@
   // code-analysis too.
   final CodegenRegistry registry;
   final Compiler compiler;
+  final GlobalTypeInferenceResults inferenceResults;
   final JavaScriptBackend backend;
   final ConstantSystem constantSystem;
   final RuntimeTypes rti;
@@ -431,7 +432,8 @@
         this.infoReporter = backend.compiler.dumpInfoTask,
         this.backend = backend,
         this.constantSystem = backend.constantSystem,
-        this.rti = backend.rti {
+        this.rti = backend.rti,
+        this.inferenceResults = backend.compiler.globalInference.results {
     assert(target.isImplementation);
     graph.element = target;
     sourceElementStack.add(target);
@@ -674,7 +676,7 @@
       // A generative constructor body is not seen by global analysis,
       // so we should not query for its type.
       if (!element.isGenerativeConstructorBody) {
-        if (compiler.globalInference.throwsAlways(element)) {
+        if (inferenceResults.throwsAlways(element)) {
           isReachable = false;
           return false;
         }
@@ -811,7 +813,7 @@
       // ConstructorBodyElements are not in the type inference graph.
       return false;
     }
-    return compiler.globalInference.isCalledOnce(element);
+    return inferenceResults.isCalledOnce(element);
   }
 
   bool isCalledOnce(Element element) {
@@ -1492,11 +1494,33 @@
 
     HInstruction newObject;
     if (!isNativeUpgradeFactory) {
-      newObject = new HCreate(
-          classElement, constructorArguments, ssaType, instantiatedTypes);
+      // Create the runtime type information, if needed.
+      bool hasRtiInput = false;
+      if (backend.classNeedsRtiField(classElement)) {
+        // Read the values of the type arguments and create a
+        // HTypeInfoExpression to set on the newly create object.
+        hasRtiInput = true;
+        List<HInstruction> typeArguments = <HInstruction>[];
+        classElement.typeVariables.forEach((TypeVariableType typeVariable) {
+            HInstruction argument = localsHandler
+                .readLocal(localsHandler.getTypeVariableAsLocal(typeVariable));
+            typeArguments.add(argument);
+          });
+
+        HInstruction typeInfo = new HTypeInfoExpression(
+            TypeInfoExpressionKind.INSTANCE,
+            classElement.thisType,
+            typeArguments,
+            backend.dynamicType);
+        add(typeInfo);
+        constructorArguments.add(typeInfo);
+      }
+
+      newObject = new HCreate(classElement, constructorArguments, ssaType,
+          instantiatedTypes: instantiatedTypes, hasRtiInput: hasRtiInput);
       if (function != null) {
-        // TODO(johnniwinther): Provide source information for creation
-        // through synthetic constructors.
+        // TODO(johnniwinther): Provide source information for creation through
+        // synthetic constructors.
         newObject.sourceInformation =
             sourceInformationBuilder.buildCreate(function);
       }
@@ -1514,26 +1538,6 @@
       }
     }
     removeInlinedInstantiation(type);
-    // Create the runtime type information, if needed.
-    if (classElement.typeVariables.isNotEmpty &&
-        backend.classNeedsRti(classElement)) {
-      // Read the values of the type arguments and create a HTypeInfoExpression
-      // to set on the newly create object.
-      List<HInstruction> typeArguments = <HInstruction>[];
-      classElement.typeVariables.forEach((TypeVariableType typeVariable) {
-        HInstruction argument = localsHandler
-            .readLocal(localsHandler.getTypeVariableAsLocal(typeVariable));
-        typeArguments.add(argument);
-      });
-
-      HInstruction typeInfo = new HTypeInfoExpression(
-          TypeInfoExpressionKind.INSTANCE,
-          classElement.thisType,
-          typeArguments,
-          backend.dynamicType);
-      add(typeInfo);
-      newObject = callSetRuntimeTypeInfo(typeInfo, newObject);
-    }
 
     // Generate calls to the constructor bodies.
     HInstruction interceptor = null;
@@ -2560,8 +2564,8 @@
       }
     }
 
-    pushInvokeDynamic(
-        node, elements.getSelector(node), elements.getTypeMask(node), [operand],
+    pushInvokeDynamic(node, elements.getSelector(node),
+        inferenceResults.typeOfSend(node, elements), [operand],
         sourceInformation: sourceInformationBuilder.buildGeneric(node));
   }
 
@@ -2588,8 +2592,12 @@
   }
 
   void handleBinary(ast.Send node, ast.Node left, ast.Node right) {
-    visitBinarySend(visitAndPop(left), visitAndPop(right),
-        elements.getSelector(node), elements.getTypeMask(node), node,
+    visitBinarySend(
+        visitAndPop(left),
+        visitAndPop(right),
+        elements.getSelector(node),
+        inferenceResults.typeOfSend(node, elements),
+        node,
         sourceInformation:
             sourceInformationBuilder.buildGeneric(node.selector));
   }
@@ -2749,8 +2757,8 @@
   /// Generate a dynamic getter invocation.
   void generateDynamicGet(ast.Send node) {
     HInstruction receiver = generateInstanceSendReceiver(node);
-    generateInstanceGetterWithCompiledReceiver(
-        node, elements.getSelector(node), elements.getTypeMask(node), receiver);
+    generateInstanceGetterWithCompiledReceiver(node, elements.getSelector(node),
+        inferenceResults.typeOfSend(node, elements), receiver);
   }
 
   /// Generate a closurization of the static or top level [function].
@@ -2799,7 +2807,7 @@
           generateInstanceGetterWithCompiledReceiver(
               node,
               elements.getSelector(node),
-              elements.getTypeMask(node),
+              inferenceResults.typeOfSend(node, elements),
               expression);
         });
   }
@@ -2870,9 +2878,7 @@
     if (selector == null) {
       assert(send != null);
       selector = elements.getSelector(send);
-      if (mask == null) {
-        mask = elements.getTypeMask(send);
-      }
+      mask ??= inferenceResults.typeOfSend(send, elements);
     }
     if (location == null) {
       assert(send != null);
@@ -3144,7 +3150,7 @@
 
   void _generateDynamicSend(ast.Send node, HInstruction receiver) {
     Selector selector = elements.getSelector(node);
-    TypeMask mask = elements.getTypeMask(node);
+    TypeMask mask = inferenceResults.typeOfSend(node, elements);
     SourceInformation sourceInformation =
         sourceInformationBuilder.buildCall(node, node.selector);
 
@@ -4031,22 +4037,19 @@
           Elements.isFilledListConstructorCall(
               originalElement, send, compiler)) {
         isFixedList = true;
-        TypeMask inferred =
-            TypeMaskFactory.inferredForNode(sourceElement, send, compiler);
+        TypeMask inferred = _inferredTypeOfNewList(send);
         return inferred.containsAll(compiler.world)
             ? backend.fixedArrayType
             : inferred;
       } else if (isGrowableListConstructorCall) {
-        TypeMask inferred =
-            TypeMaskFactory.inferredForNode(sourceElement, send, compiler);
+        TypeMask inferred = _inferredTypeOfNewList(send);
         return inferred.containsAll(compiler.world)
             ? backend.extendableArrayType
             : inferred;
       } else if (Elements.isConstructorOfTypedArraySubclass(
           originalElement, compiler)) {
         isFixedList = true;
-        TypeMask inferred =
-            TypeMaskFactory.inferredForNode(sourceElement, send, compiler);
+        TypeMask inferred = _inferredTypeOfNewList(send);
         ClassElement cls = element.enclosingClass;
         assert(backend.isNative(cls.thisType.element));
         return inferred.containsAll(compiler.world)
@@ -4178,7 +4181,7 @@
               ? native.NativeThrowBehavior.MAY
               : native.NativeThrowBehavior.NEVER);
       push(foreign);
-      if (compiler.globalInference.isFixedArrayCheckedForGrowable(send)) {
+      if (inferenceResults.isFixedArrayCheckedForGrowable(send)) {
         js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array');
         // We set the instruction as [canThrow] to avoid it being dead code.
         // We need a finer grained side effect.
@@ -4923,7 +4926,7 @@
         receiver,
         rhs,
         elements.getOperatorSelectorInComplexSendSet(node),
-        elements.getOperatorTypeMaskInComplexSendSet(node),
+        inferenceResults.typeOfOperator(node, elements),
         node,
         sourceInformation:
             sourceInformationBuilder.buildGeneric(node.assignmentOperator));
@@ -5287,7 +5290,7 @@
       }
 
       pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node),
-          elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]);
+          inferenceResults.typeOfGetter(node, elements), [receiver, index]);
       HInstruction getterInstruction = pop();
       if (node.isIfNullAssignment) {
         // Compile x[i] ??= e as:
@@ -5299,16 +5302,22 @@
         brancher.handleIfNull(() => stack.add(getterInstruction), () {
           visit(arguments.head);
           HInstruction value = pop();
-          pushInvokeDynamic(node, elements.getSelector(node),
-              elements.getTypeMask(node), [receiver, index, value]);
+          pushInvokeDynamic(
+              node,
+              elements.getSelector(node),
+              inferenceResults.typeOfSend(node, elements),
+              [receiver, index, value]);
           pop();
           stack.add(value);
         });
       } else {
         handleComplexOperatorSend(node, getterInstruction, arguments);
         HInstruction value = pop();
-        pushInvokeDynamic(node, elements.getSelector(node),
-            elements.getTypeMask(node), [receiver, index, value]);
+        pushInvokeDynamic(
+            node,
+            elements.getSelector(node),
+            inferenceResults.typeOfSend(node, elements),
+            [receiver, index, value]);
         pop();
         if (node.isPostfix) {
           stack.add(getterInstruction);
@@ -5512,7 +5521,7 @@
         generateInstanceGetterWithCompiledReceiver(
             node,
             elements.getGetterSelectorInComplexSendSet(node),
-            elements.getGetterTypeMaskInComplexSendSet(node),
+            inferenceResults.typeOfGetter(node, elements),
             receiver);
         HInstruction getterInstruction = pop();
         if (node.isIfNullAssignment) {
@@ -5967,12 +5976,15 @@
       instruction = setRtiIfNeeded(instruction, node);
     }
 
-    TypeMask type =
-        TypeMaskFactory.inferredForNode(sourceElement, node, compiler);
+    TypeMask type = _inferredTypeOfNewList(node);
     if (!type.containsAll(compiler.world)) instruction.instructionType = type;
     stack.add(instruction);
   }
 
+  _inferredTypeOfNewList(ast.Node node) =>
+      inferenceResults.typeOfNewList(sourceElement, node) ??
+      compiler.commonMasks.dynamicType;
+
   visitConditional(ast.Conditional node) {
     SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node);
     brancher.handleConditional(() => visit(node.condition),
@@ -6066,7 +6078,7 @@
 
     HInstruction buildCondition() {
       Selector selector = Selectors.moveNext;
-      TypeMask mask = elements.getMoveNextTypeMask(node);
+      TypeMask mask = inferenceResults.typeOfIteratorMoveNext(node, elements);
       pushInvokeDynamic(node, selector, mask, [streamIterator]);
       HInstruction future = pop();
       push(new HAwait(future,
@@ -6076,17 +6088,17 @@
 
     void buildBody() {
       Selector call = Selectors.current;
-      TypeMask callMask = elements.getCurrentTypeMask(node);
+      TypeMask callMask =
+          inferenceResults.typeOfIteratorCurrent(node, elements);
       pushInvokeDynamic(node, call, callMask, [streamIterator]);
 
       ast.Node identifier = node.declaredIdentifier;
       Element variable = elements.getForInVariable(node);
       Selector selector = elements.getSelector(identifier);
-      TypeMask mask = elements.getTypeMask(identifier);
-
       HInstruction value = pop();
       if (identifier.asSend() != null &&
           Elements.isInstanceSend(identifier, elements)) {
+        TypeMask mask = inferenceResults.typeOfSend(identifier, elements);
         HInstruction receiver = generateInstanceSendReceiver(identifier);
         assert(receiver != null);
         generateInstanceSetterWithCompiledReceiver(null, receiver, value,
@@ -6100,7 +6112,6 @@
     }
 
     void buildUpdate() {}
-    ;
 
     buildProtectedByFinally(() {
       handleLoop(
@@ -6124,7 +6135,7 @@
     // method is inlined.  We would require full scalar replacement in that
     // case.
 
-    TypeMask mask = elements.getIteratorTypeMask(node);
+    TypeMask mask = inferenceResults.typeOfIterator(node, elements);
 
     ClassWorld classWorld = compiler.world;
     if (mask != null &&
@@ -6149,7 +6160,7 @@
 
     void buildInitializer() {
       Selector selector = Selectors.iterator;
-      TypeMask mask = elements.getIteratorTypeMask(node);
+      TypeMask mask = inferenceResults.typeOfIterator(node, elements);
       visit(node.expression);
       HInstruction receiver = pop();
       pushInvokeDynamic(node, selector, mask, [receiver]);
@@ -6158,14 +6169,14 @@
 
     HInstruction buildCondition() {
       Selector selector = Selectors.moveNext;
-      TypeMask mask = elements.getMoveNextTypeMask(node);
+      TypeMask mask = inferenceResults.typeOfIteratorMoveNext(node, elements);
       pushInvokeDynamic(node, selector, mask, [iterator]);
       return popBoolified();
     }
 
     void buildBody() {
       Selector call = Selectors.current;
-      TypeMask mask = elements.getCurrentTypeMask(node);
+      TypeMask mask = inferenceResults.typeOfIteratorCurrent(node, elements);
       pushInvokeDynamic(node, call, mask, [iterator]);
       buildAssignLoopVariable(node, pop());
       visit(node.body);
@@ -6178,10 +6189,10 @@
     ast.Node identifier = node.declaredIdentifier;
     Element variable = elements.getForInVariable(node);
     Selector selector = elements.getSelector(identifier);
-    TypeMask mask = elements.getTypeMask(identifier);
 
     if (identifier.asSend() != null &&
         Elements.isInstanceSend(identifier, elements)) {
+      TypeMask mask = inferenceResults.typeOfSend(identifier, elements);
       HInstruction receiver = generateInstanceSendReceiver(identifier);
       assert(receiver != null);
       generateInstanceSetterWithCompiledReceiver(null, receiver, value,
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 346a168..fc4dc48 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -298,7 +298,7 @@
     TypeMask type = astAdapter.selectorTypeOf(invocation);
 
     push(new HInvokeDynamicMethod(astAdapter.getSelector(invocation),
-        astAdapter.getTypeMask(invocation), inputs, type, isIntercepted));
+        astAdapter.typeOfInvocation(invocation), inputs, type, isIntercepted));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index abd0314..6faf0b4 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1943,12 +1943,7 @@
     if (node.element.isClosure) {
       registry.registerInstantiatedClass(node.element);
     }
-    if (node.instantiatedTypes == null) {
-      return;
-    }
-    node.instantiatedTypes.forEach((type) {
-      registry.registerInstantiation(type);
-    });
+    node.instantiatedTypes?.forEach(registry.registerInstantiation);
   }
 
   js.Expression newLiteralBool(
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index a12a57e..10202de 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -300,12 +300,16 @@
       return false;
     }
 
+    // If it is a conditional constant interceptor and was not strengthened to a
+    // constant interceptor then there is nothing more we can do.
+    if (node.isConditionalConstantInterceptor) return false;
+
     // Do we have an 'almost constant' interceptor?  The receiver could be
     // `null` but not any other JavaScript falsy value, `null` values cause
     // `NoSuchMethodError`s, and if the receiver was not null we would have a
     // constant interceptor `C`.  Then we can use `(receiver && C)` for the
     // interceptor.
-    if (receiver.canBeNull() && !node.isConditionalConstantInterceptor) {
+    if (receiver.canBeNull()) {
       if (!interceptedClasses.contains(helpers.jsNullClass)) {
         // Can use `(receiver && C)` only if receiver is either null or truthy.
         if (!(receiver.canBePrimitiveNumber(compiler) ||
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index 6c3c8355..719b346 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -100,13 +100,14 @@
     return new Selector(kind, name, callStructure);
   }
 
-  TypeMask getTypeMask(ir.MethodInvocation invocation) {
-    return _elements.getTypeMask(getNode(invocation));
+  TypeMask typeOfInvocation(ir.MethodInvocation invocation) {
+    return _compiler.globalInference.results
+        .typeOfSend(getNode(invocation), _elements);
   }
 
   TypeMask selectorTypeOf(ir.MethodInvocation invocation) {
     return TypeMaskFactory.inferredTypeForSelector(
-        getSelector(invocation), getTypeMask(invocation), _compiler);
+        getSelector(invocation), typeOfInvocation(invocation), _compiler);
   }
 
   bool isIntercepted(ir.MethodInvocation invocation) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 3fec3f8..e3342cd 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -1504,6 +1504,9 @@
 class HCreate extends HInstruction {
   final ClassElement element;
 
+  /// Does this instruction have reified type information as the last input?
+  final bool hasRtiInput;
+
   /// If this field is not `null`, this call is from an inlined constructor and
   /// we have to register the instantiated type in the code generator. The
   /// [instructionType] of this node is not enough, because we also need the
@@ -1511,14 +1514,19 @@
   List<DartType> instantiatedTypes;
 
   HCreate(this.element, List<HInstruction> inputs, TypeMask type,
-      [this.instantiatedTypes])
+      {this.instantiatedTypes, this.hasRtiInput: false})
       : super(inputs, type);
 
-  accept(HVisitor visitor) => visitor.visitCreate(this);
-
   bool get isAllocation => true;
 
-  String toString() => 'HCreate($element)';
+  HInstruction get rtiInput {
+    assert(hasRtiInput);
+    return inputs.last;
+  }
+
+  accept(HVisitor visitor) => visitor.visitCreate(this);
+
+  String toString() => 'HCreate($element, ${instantiatedTypes})';
 }
 
 abstract class HInvoke extends HInstruction {
@@ -2623,6 +2631,10 @@
   HInstruction get receiver => inputs[0];
   HInstruction get index => inputs[1];
 
+  // Implicit dependency on HBoundsCheck or constraints on index.
+  // TODO(27272): Make HIndex dependent on bounds checking.
+  bool get isMovable => false;
+
   HInstruction getDartReceiver(Compiler compiler) => receiver;
   bool onlyThrowsNSM() => true;
   bool canThrow() => receiver.canBeNull();
@@ -2653,6 +2665,10 @@
   HInstruction get index => inputs[1];
   HInstruction get value => inputs[2];
 
+  // Implicit dependency on HBoundsCheck or constraints on index.
+  // TODO(27272): Make HIndex dependent on bounds checking.
+  bool get isMovable => false;
+
   HInstruction getDartReceiver(Compiler compiler) => receiver;
   bool onlyThrowsNSM() => true;
   bool canThrow() => receiver.canBeNull();
@@ -3322,7 +3338,7 @@
     return kind == other.kind && dartType == other.dartType;
   }
 
-  String toString() => 'HTypeInfoExpression $kindAsString $dartType';
+  String toString() => 'HTypeInfoExpression($kindAsString, $dartType)';
 
   String get kindAsString {
     switch (kind) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index f15dceb..3ac8e27 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.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 '../common/codegen.dart' show CodegenWorkItem;
+import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../constants/constant_system.dart';
@@ -50,21 +50,23 @@
 
     ConstantSystem constantSystem = compiler.backend.constantSystem;
     bool trustPrimitives = compiler.options.trustPrimitives;
+    CodegenRegistry registry = work.registry;
     Set<HInstruction> boundsChecked = new Set<HInstruction>();
+    SsaCodeMotion codeMotion;
     measure(() {
       List<OptimizationPhase> phases = <OptimizationPhase>[
         // Run trivial instruction simplification first to optimize
         // some patterns useful for type conversion.
-        new SsaInstructionSimplifier(constantSystem, backend, this),
+        new SsaInstructionSimplifier(constantSystem, backend, this, registry),
         new SsaTypeConversionInserter(compiler),
         new SsaRedundantPhiEliminator(),
         new SsaDeadPhiEliminator(),
         new SsaTypePropagator(compiler),
         // After type propagation, more instructions can be
         // simplified.
-        new SsaInstructionSimplifier(constantSystem, backend, this),
+        new SsaInstructionSimplifier(constantSystem, backend, this, registry),
         new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
-        new SsaInstructionSimplifier(constantSystem, backend, this),
+        new SsaInstructionSimplifier(constantSystem, backend, this, registry),
         new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
         new SsaTypePropagator(compiler),
         // Run a dead code eliminator before LICM because dead
@@ -74,7 +76,7 @@
         // After GVN, some instructions might need their type to be
         // updated because they now have different inputs.
         new SsaTypePropagator(compiler),
-        new SsaCodeMotion(),
+        codeMotion = new SsaCodeMotion(),
         new SsaLoadElimination(compiler),
         new SsaRedundantPhiEliminator(),
         new SsaDeadPhiEliminator(),
@@ -82,7 +84,7 @@
         new SsaValueRangeAnalyzer(compiler, constantSystem, this),
         // Previous optimizations may have generated new
         // opportunities for instruction simplification.
-        new SsaInstructionSimplifier(constantSystem, backend, this),
+        new SsaInstructionSimplifier(constantSystem, backend, this, registry),
         new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
       ];
       phases.forEach(runPhase);
@@ -95,13 +97,13 @@
 
       SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(compiler, this);
       runPhase(dce);
-      if (dce.eliminatedSideEffects) {
+      if (codeMotion.movedCode || dce.eliminatedSideEffects) {
         phases = <OptimizationPhase>[
           new SsaTypePropagator(compiler),
           new SsaGlobalValueNumberer(compiler),
           new SsaCodeMotion(),
           new SsaValueRangeAnalyzer(compiler, constantSystem, this),
-          new SsaInstructionSimplifier(constantSystem, backend, this),
+          new SsaInstructionSimplifier(constantSystem, backend, this, registry),
           new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
           new SsaSimplifyInterceptors(compiler, constantSystem, work.element),
           new SsaDeadCodeEliminator(compiler, this),
@@ -111,7 +113,7 @@
           new SsaTypePropagator(compiler),
           // Run the simplifier to remove unneeded type checks inserted by
           // type propagation.
-          new SsaInstructionSimplifier(constantSystem, backend, this),
+          new SsaInstructionSimplifier(constantSystem, backend, this, registry),
         ];
       }
       phases.forEach(runPhase);
@@ -154,11 +156,13 @@
   final String name = "SsaInstructionSimplifier";
   final JavaScriptBackend backend;
   final ConstantSystem constantSystem;
+  final CodegenRegistry registry;
   HGraph graph;
   Compiler get compiler => backend.compiler;
   final SsaOptimizerTask optimizer;
 
-  SsaInstructionSimplifier(this.constantSystem, this.backend, this.optimizer);
+  SsaInstructionSimplifier(
+      this.constantSystem, this.backend, this.optimizer, this.registry);
 
   CoreClasses get coreClasses => compiler.coreClasses;
 
@@ -1158,36 +1162,44 @@
 
     // Match:
     //
-    //     setRuntimeTypeInfo(
-    //         HCreate(ClassElement),
-    //         HTypeInfoExpression(t_0, t_1, t_2, ...));
+    //     HCreate(ClassElement,
+    //       [arg_i,
+    //        ...,
+    //        HTypeInfoExpression(t_0, t_1, t_2, ...)]);
     //
     // The `t_i` are the values of the type parameters of ClassElement.
-    if (object is HInvokeStatic) {
-      if (object.element == helpers.setRuntimeTypeInfo) {
-        HInstruction allocation = object.inputs[0];
-        if (allocation is HCreate) {
-          HInstruction typeInfo = object.inputs[1];
-          if (typeInfo is HTypeInfoExpression) {
-            return finishSubstituted(
-                allocation.element, (int index) => typeInfo.inputs[index]);
-          }
-        }
-        return node;
+
+    if (object is HCreate) {
+      void registerInstantiations() {
+        // Forwarding the type variable references might cause the HCreate to
+        // become dead. This breaks the algorithm for generating the per-type
+        // runtime type information, so we instantiate them here in case the
+        // HCreate becomes dead.
+        object.instantiatedTypes?.forEach(registry.registerInstantiation);
       }
-      // TODO(sra): Factory constructors pass type arguments after the value
-      // arguments. The [select] argument indexes into these type arguments.
+
+      if (object.hasRtiInput) {
+        HInstruction typeInfo = object.rtiInput;
+        if (typeInfo is HTypeInfoExpression) {
+          registerInstantiations();
+          return finishSubstituted(
+              object.element, (int index) => typeInfo.inputs[index]);
+        }
+      } else {
+        // Non-generic type (which extends or mixes in a generic type, for
+        // example CodeUnits extends UnmodifiableListBase<int>).  Also used for
+        // raw-type when the type parameters are elided.
+        registerInstantiations();
+        return finishSubstituted(
+            object.element,
+            // If there are type arguments, all type arguments are 'dynamic'.
+            (int i) => graph.addConstantNull(compiler));
+      }
     }
 
-    // Non-generic type (which extends or mixes in a generic type, for example
-    // CodeUnits extends UnmodifiableListBase<int>).
-    // Also used for raw-type when the type parameters are elided.
-    if (object is HCreate) {
-      return finishSubstituted(
-          object.element,
-          // If there are type arguments, all type arguments are 'dynamic'.
-          (int i) => graph.addConstantNull(compiler));
-    }
+    // TODO(sra): Factory constructors pass type arguments after the value
+    // arguments. The [selectTypeArgumentFromObjectCreation] argument of
+    // [finishSubstituted] indexes into these type arguments.
 
     return node;
   }
@@ -1913,6 +1925,7 @@
 class SsaCodeMotion extends HBaseVisitor implements OptimizationPhase {
   final String name = "SsaCodeMotion";
 
+  bool movedCode = false;
   List<ValueSet> values;
 
   void visitGraph(HGraph graph) {
@@ -1949,6 +1962,7 @@
             if (toRewrite != instruction) {
               successor.rewriteWithBetterUser(toRewrite, instruction);
               successor.remove(toRewrite);
+              movedCode = true;
             }
           }
         }
@@ -1992,6 +2006,7 @@
       } else {
         block.rewriteWithBetterUser(current, existing);
         block.remove(current);
+        movedCode = true;
       }
     }
   }
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 3722bf5..f43ca7e 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -14,25 +14,18 @@
 class TypeMaskFactory {
   static TypeMask inferredReturnTypeForElement(
       Element element, Compiler compiler) {
-    return compiler.globalInference.getGuaranteedReturnTypeOfElement(element) ??
+    return compiler.globalInference.results.returnTypeOf(element) ??
         compiler.commonMasks.dynamicType;
   }
 
   static TypeMask inferredTypeForElement(Element element, Compiler compiler) {
-    return compiler.globalInference.getGuaranteedTypeOfElement(element) ??
+    return compiler.globalInference.results.typeOf(element) ??
         compiler.commonMasks.dynamicType;
   }
 
   static TypeMask inferredTypeForSelector(
       Selector selector, TypeMask mask, Compiler compiler) {
-    return compiler.globalInference
-            .getGuaranteedTypeOfSelector(selector, mask) ??
-        compiler.commonMasks.dynamicType;
-  }
-
-  static TypeMask inferredForNode(
-      Element owner, ast.Node node, Compiler compiler) {
-    return compiler.globalInference.getGuaranteedTypeOfNode(owner, node) ??
+    return compiler.globalInference.results.typeOfSelector(selector, mask) ??
         compiler.commonMasks.dynamicType;
   }
 
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index 28dc608..ad890dc 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -9,6 +9,7 @@
 import '../elements/elements.dart';
 import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
 import '../tree/tree.dart';
+import '../resolution/tree_elements.dart';
 import '../universe/selector.dart' show Selector;
 
 import 'masks.dart';
@@ -19,13 +20,108 @@
   void analyzeMain(Element element);
   TypeMask getReturnTypeOfElement(Element element);
   TypeMask getTypeOfElement(Element element);
-  TypeMask getTypeOfNode(Element owner, Node node);
+  TypeMask getTypeForNewList(Element owner, Node node);
   TypeMask getTypeOfSelector(Selector selector, TypeMask mask);
   void clear();
   bool isCalledOnce(Element element);
   bool isFixedArrayCheckedForGrowable(Node node);
 }
 
+/// Results produced by the global type-inference algorithm.
+///
+/// All queries in this class may contain results that assume whole-program
+/// closed-world semantics. Any [TypeMask] for an element or node that we return
+/// was inferred to be a "guaranteed type", that means, it is a type that we
+/// can prove to be correct for all executions of the program.
+class GlobalTypeInferenceResults {
+  // TODO(sigmund): store relevant data & drop reference to inference engine.
+  final TypesInferrer _inferrer;
+  final Compiler compiler;
+  final TypeMask dynamicType;
+
+  GlobalTypeInferenceResults(this._inferrer, this.compiler, CommonMasks masks)
+      : dynamicType = masks.dynamicType;
+
+  /// Returns the type of a parameter or field [element], if any.
+  TypeMask typeOf(Element element) {
+    // TODO(24489): trust some JsInterop types.
+    if (compiler.backend.isJsInterop(element)) return dynamicType;
+    return _inferrer.getTypeOfElement(element);
+  }
+
+  /// Returns the return type of a method or function [element].
+  TypeMask returnTypeOf(Element element) {
+    // TODO(24489): trust some JsInterop types.
+    if (compiler.backend.isJsInterop(element)) return dynamicType;
+    return _inferrer.getReturnTypeOfElement(element);
+  }
+
+  /// Returns the type of a [selector] when applied to a receiver with the given
+  /// type [mask].
+  TypeMask typeOfSelector(Selector selector, TypeMask mask) =>
+      _inferrer.getTypeOfSelector(selector, mask);
+
+  /// Returns whether the method [element] always throws.
+  bool throwsAlways(Element element) {
+    // We know the element always throws if the return type was inferred to be
+    // non-null empty.
+    TypeMask returnType = returnTypeOf(element);
+    return returnType != null && returnType.isEmpty;
+  }
+
+  /// Returns whether [element] is only called once in the entire program.
+  bool isCalledOnce(Element element) => _inferrer.isCalledOnce(element);
+
+  // TODO(sigmund): introduce a new class [ElementInferenceResult] that can be
+  // used to collect any information that is specific about the body within a
+  // single element (basically everything below this line). We could consider
+  // moving some of the functions above too, for example:
+  //    results.throwsAlways(element)
+  // could become:
+  //    results[element].alwaysThrows;
+  //
+
+  /// Returns the type of a list allocation [node] occuring within [owner].
+  ///
+  /// [node] can be a list literal or a list new expression.
+  TypeMask typeOfNewList(Element owner, Node node) =>
+      _inferrer.getTypeForNewList(owner, node);
+
+  /// Returns whether a fixed-length constructor call goes through a growable
+  /// check.
+  bool isFixedArrayCheckedForGrowable(Node ctorCall) =>
+      _inferrer.isFixedArrayCheckedForGrowable(ctorCall);
+
+  /// Returns the type of a send [node].
+  TypeMask typeOfSend(
+          Node node,
+          // TODO(sigmund): move inference data out of TreeElements
+          TreeElements elements) =>
+      elements.getTypeMask(node);
+
+  /// Returns the type of the operator of a complex send-set [node], for
+  /// example, the type of `+` in `a += b`.
+  TypeMask typeOfOperator(Send node, TreeElements elements) =>
+      elements.getOperatorTypeMaskInComplexSendSet(node);
+
+  /// Returns the type of the getter in a complex send-set [node], for example,
+  /// the type of the `a.f` getter in `a.f += b`.
+  TypeMask typeOfGetter(node, elements) =>
+      elements.getGetterTypeMaskInComplexSendSet(node);
+
+  /// Returns the type of the iterator in a [loop].
+  TypeMask typeOfIterator(ForIn loop, elements) =>
+      elements.getIteratorTypeMask(loop);
+
+  /// Returns the type of the `moveNext` call of an iterator in a [loop].
+  TypeMask typeOfIteratorMoveNext(ForIn loop, elements) =>
+      elements.getMoveNextTypeMask(loop);
+
+  /// Returns the type of the `current` getter of an iterator in a [loop].
+  TypeMask typeOfIteratorCurrent(ForIn node, elements) =>
+      elements.getCurrentTypeMask(node);
+}
+
 /// Global analysis that infers concrete types.
 class GlobalTypeInferenceTask extends CompilerTask {
   // TODO(sigmund): rename at the same time as our benchmarking tools.
@@ -34,6 +130,7 @@
   final Compiler compiler;
   TypesInferrer typesInferrer;
   CommonMasks masks;
+  GlobalTypeInferenceResults results;
 
   GlobalTypeInferenceTask(Compiler compiler)
       : masks = new CommonMasks(compiler),
@@ -47,59 +144,7 @@
     measure(() {
       typesInferrer.analyzeMain(mainElement);
       typesInferrer.clear();
+      results = new GlobalTypeInferenceResults(typesInferrer, compiler, masks);
     });
   }
-
-  /**
-   * Return the (inferred) guaranteed type of [element] or null.
-   */
-  TypeMask getGuaranteedTypeOfElement(Element element) {
-    // TODO(24489): trust some JsInterop types.
-    if (compiler.backend.isJsInterop(element)) {
-      return masks.dynamicType;
-    }
-    TypeMask guaranteedType = typesInferrer.getTypeOfElement(element);
-    return guaranteedType;
-  }
-
-  TypeMask getGuaranteedReturnTypeOfElement(Element element) {
-    // TODO(24489): trust some JsInterop types.
-    if (compiler.backend.isJsInterop(element)) {
-      return masks.dynamicType;
-    }
-
-    TypeMask guaranteedType = typesInferrer.getReturnTypeOfElement(element);
-    return guaranteedType;
-  }
-
-  /// Return whether the global inference algorithm determined that [element]
-  /// always throws.
-  bool throwsAlways(Element element) {
-    // We know the element always throws if the return type was inferred to be
-    // non-null empty.
-    TypeMask returnType = getGuaranteedReturnTypeOfElement(element);
-    return returnType != null && returnType.isEmpty;
-  }
-
-  bool isFixedArrayCheckedForGrowable(Node send) =>
-      typesInferrer.isFixedArrayCheckedForGrowable(send);
-
-  bool isCalledOnce(Element element) => typesInferrer.isCalledOnce(element);
-
-  /**
-   * Return the (inferred) guaranteed type of [node] or null.
-   * [node] must be an AST node of [owner].
-   */
-  TypeMask getGuaranteedTypeOfNode(owner, node) {
-    TypeMask guaranteedType = typesInferrer.getTypeOfNode(owner, node);
-    return guaranteedType;
-  }
-
-  /**
-   * Return the (inferred) guaranteed type of [selector] or null.
-   */
-  TypeMask getGuaranteedTypeOfSelector(Selector selector, TypeMask mask) {
-    TypeMask guaranteedType = typesInferrer.getTypeOfSelector(selector, mask);
-    return guaranteedType;
-  }
 }
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 87090de..527240f 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -18,6 +18,7 @@
         MixinApplicationElement,
         TypedefElement,
         VariableElement;
+import 'js_backend/backend.dart' show JavaScriptBackend;
 import 'ordered_typeset.dart';
 import 'types/masks.dart' show TypeMask, FlatTypeMask;
 import 'universe/class_set.dart';
@@ -405,6 +406,9 @@
 
   @override
   ClassElement getLubOfInstantiatedSubclasses(ClassElement cls) {
+    if (backend.isJsInterop(cls)) {
+      return backend.helpers.jsJavaScriptObjectClass;
+    }
     ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration];
     return hierarchy != null
         ? hierarchy.getLubOfInstantiatedSubclasses()
@@ -413,6 +417,9 @@
 
   @override
   ClassElement getLubOfInstantiatedSubtypes(ClassElement cls) {
+    if (backend.isJsInterop(cls)) {
+      return backend.helpers.jsJavaScriptObjectClass;
+    }
     ClassSet classSet = _classSets[cls.declaration];
     return classSet != null ? classSet.getLubOfInstantiatedSubtypes() : null;
   }
@@ -548,7 +555,7 @@
   }
 
   final Compiler compiler;
-  Backend get backend => compiler.backend;
+  JavaScriptBackend get backend => compiler.backend;
   final FunctionSet allFunctions;
   final Set<Element> functionsCalledInLoop = new Set<Element>();
   final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>();
diff --git a/pkg/dev_compiler/.travis.yml b/pkg/dev_compiler/.travis.yml
deleted file mode 100644
index 676e53b..0000000
--- a/pkg/dev_compiler/.travis.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-language: dart
-sudo: false
-dart:
-  - dev
-cache:
-  directories:
-    - $HOME/.npm
-    - $HOME/.nvm
-    - $HOME/.pub-cache/hosted
-    - node_modules
-before_install:
-  - test "$ANALYZER" != master -a "$ANALYZER" != dev || ./tool/override_analyzer_dependency.sh $ANALYZER
-  - pub global activate dart_coveralls
-  - export CHROME_CANARY_BIN=`./tool/get_chrome_canary.sh`
-  - export DISPLAY=:99.0
-  - sh -e /etc/init.d/xvfb start
-before_script:
-  - nvm install 5.5.0
-  - npm install
-script:
-  - if [[ -z "$TEST" ]]; then ./tool/presubmit.sh ; fi
-  - if [[ "$TEST" == coverage ]]; then ./tool/build_sdk.sh && ./tool/coverage.sh ; fi
-  - if [[ "$TEST" == node ]]; then ./tool/node_test.sh ; fi
-env:
-  - ANALYZER=stable
-  - ANALYZER=master
-  - ANALYZER=dev
-  - TEST=coverage
-  - TEST=node
-matrix:
-  allow_failures:
-    - env: ANALYZER=master
-    - env: TEST=node
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index 7d20a62..7d8c1b8 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -34,7 +34,7 @@
   let JSArrayOfListOfObject = () => (JSArrayOfListOfObject = dart.constFn(_interceptors.JSArray$(ListOfObject())))();
   let JSArrayOfObject = () => (JSArrayOfObject = dart.constFn(_interceptors.JSArray$(core.Object)))();
   let MapOfSymbol$dynamic = () => (MapOfSymbol$dynamic = dart.constFn(core.Map$(core.Symbol, dart.dynamic)))();
-  let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
+  let MapOfString$_MethodStats = () => (MapOfString$_MethodStats = dart.constFn(core.Map$(core.String, dart._MethodStats)))();
   let ListOfString = () => (ListOfString = dart.constFn(core.List$(core.String)))();
   let SetOfNameValuePair = () => (SetOfNameValuePair = dart.constFn(core.Set$(_debugger.NameValuePair)))();
   let JSArrayOfNameValuePair = () => (JSArrayOfNameValuePair = dart.constFn(_interceptors.JSArray$(_debugger.NameValuePair)))();
@@ -119,6 +119,7 @@
   let TimerTovoid = () => (TimerTovoid = dart.constFn(dart.functionType(dart.void, [async.Timer])))();
   let MapOfdynamic$int = () => (MapOfdynamic$int = dart.constFn(core.Map$(dart.dynamic, core.int)))();
   let dynamicTodynamic = () => (dynamicTodynamic = dart.constFn(dart.functionType(dart.dynamic, [dart.dynamic])))();
+  let InternalMap = () => (InternalMap = dart.constFn(_js_helper.InternalMap$()))();
   let JSArrayOfint = () => (JSArrayOfint = dart.constFn(_interceptors.JSArray$(core.int)))();
   let ListOfint = () => (ListOfint = dart.constFn(core.List$(core.int)))();
   let SyncIterator = () => (SyncIterator = dart.constFn(_js_helper.SyncIterator$()))();
@@ -513,6 +514,7 @@
   let MapOfString$Function = () => (MapOfString$Function = dart.constFn(core.Map$(core.String, core.Function)))();
   let JSArrayOfKeyEvent = () => (JSArrayOfKeyEvent = dart.constFn(_interceptors.JSArray$(html$.KeyEvent)))();
   let ListOfKeyEvent = () => (ListOfKeyEvent = dart.constFn(core.List$(html$.KeyEvent)))();
+  let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
   let JSArrayOfNodeValidator = () => (JSArrayOfNodeValidator = dart.constFn(_interceptors.JSArray$(html$.NodeValidator)))();
   let ListOfNodeValidator = () => (ListOfNodeValidator = dart.constFn(core.List$(html$.NodeValidator)))();
   let _WrappedList = () => (_WrappedList = dart.constFn(html$._WrappedList$()))();
@@ -531,6 +533,7 @@
   let CompleterOfAudioBuffer = () => (CompleterOfAudioBuffer = dart.constFn(async.Completer$(web_audio.AudioBuffer)))();
   let EventStreamProviderOfAudioProcessingEvent = () => (EventStreamProviderOfAudioProcessingEvent = dart.constFn(html$.EventStreamProvider$(web_audio.AudioProcessingEvent)))();
   let StringAndStringToint = () => (StringAndStringToint = dart.constFn(dart.definiteFunctionType(core.int, [core.String, core.String])))();
+  let VoidTo_MethodStats = () => (VoidTo_MethodStats = dart.constFn(dart.definiteFunctionType(dart._MethodStats, [])))();
   let dynamicTodynamic$ = () => (dynamicTodynamic$ = dart.constFn(dart.definiteFunctionType(dart.dynamic, [dart.dynamic])))();
   let dynamicToString = () => (dynamicToString = dart.constFn(dart.definiteFunctionType(core.String, [dart.dynamic])))();
   let dynamicToListOfString = () => (dynamicToListOfString = dart.constFn(dart.definiteFunctionType(ListOfString(), [dart.dynamic])))();
@@ -560,6 +563,7 @@
   let FunctionTovoid = () => (FunctionTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Function])))();
   let StringAndStringToString$ = () => (StringAndStringToString$ = dart.constFn(dart.definiteFunctionType(core.String, [core.String, core.String])))();
   let TypeAndStringTodynamic = () => (TypeAndStringTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [core.Type, core.String])))();
+  let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
   let ListOfEToListOfE = () => (ListOfEToListOfE = dart.constFn(dart.definiteFunctionType(E => [core.List$(E), [core.List$(E)]])))();
   let StringTovoid$ = () => (StringTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [core.String])))();
   let _IsolateContextAndFunctionTodynamic = () => (_IsolateContextAndFunctionTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [_isolate_helper._IsolateContext, core.Function])))();
@@ -670,7 +674,6 @@
   let ObjectToint = () => (ObjectToint = dart.constFn(dart.definiteFunctionType(core.int, [core.Object])))();
   let ObjectTovoid = () => (ObjectTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Object])))();
   let StringAndStringTovoid$ = () => (StringAndStringTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [core.String, core.String])))();
-  let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
   let MapOfString$StringAndStringToMapOfString$String = () => (MapOfString$StringAndStringToMapOfString$String = dart.constFn(dart.definiteFunctionType(MapOfString$String(), [MapOfString$String(), core.String])))();
   let intAndintAndintTovoid = () => (intAndintAndintTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.int, core.int, core.int])))();
   let String__Tovoid = () => (String__Tovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.String], [dart.dynamic])))();
@@ -1448,7 +1451,7 @@
   };
   dart.dload = function(obj, field) {
     let f = dart._canonicalMember(obj, field);
-    dart._trackCall(obj, f);
+    dart._trackCall(obj);
     if (f != null) {
       if (dart.test(dart.hasMethod(obj, f))) return dart.bind(obj, f, void 0);
       return obj[f];
@@ -1457,7 +1460,7 @@
   };
   dart.dput = function(obj, field, value) {
     let f = dart._canonicalMember(obj, field);
-    dart._trackCall(obj, f);
+    dart._trackCall(obj);
     if (f != null) {
       return obj[f] = value;
     }
@@ -1505,7 +1508,7 @@
     return null;
   };
   dart._checkAndCall = function(f, ftype, obj, typeArgs, args, name) {
-    dart._trackCall(obj, name);
+    dart._trackCall(obj);
     let originalTarget = obj === void 0 ? f : obj;
     function callNSM() {
       return dart.noSuchMethod(originalTarget, new dart.InvocationImpl(name, args, {namedArguments: dart.extractNamedArgs(args), isMethod: true}));
@@ -1556,17 +1559,17 @@
   dart.getDynamicStats = function() {
     let ret = JSArrayOfListOfObject().of([]);
     let keys = dart._callMethodStats[dartx.keys][dartx.toList]();
-    keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b)[dartx.compareTo](dart._callMethodStats[dartx.get](a)), StringAndStringToint()));
+    keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b).count[dartx.compareTo](dart._callMethodStats[dartx.get](a).count), StringAndStringToint()));
     for (let key of keys) {
-      let count = dart._callMethodStats[dartx.get](key);
-      ret[dartx.add](JSArrayOfObject().of([key, count]));
+      let stats = dart._callMethodStats[dartx.get](key);
+      ret[dartx.add](JSArrayOfObject().of([stats.typeName, stats.frame, stats.count]));
     }
     return ret;
   };
   dart.clearDynamicStats = function() {
     dart._callMethodStats[dartx.clear]();
   };
-  dart._trackCall = function(obj, name) {
+  dart._trackCall = function(obj) {
     if (!dart.trackProfile) return;
     let actual = dart.getReifiedType(obj);
     let stackStr = new Error().stack;
@@ -1579,12 +1582,9 @@
         break;
       }
     }
-    name = dart.str`${dart.typeName(actual)}.${name} <${src}>`;
-    if (dart.test(dart._callMethodStats[dartx.containsKey](name))) {
-      dart._callMethodStats[dartx.set](core.String._check(name), dart.notNull(dart._callMethodStats[dartx.get](name)) + 1);
-    } else {
-      dart._callMethodStats[dartx.set](core.String._check(name), 1);
-    }
+    let actualTypeName = dart.typeName(actual);
+    let o = dart._callMethodStats[dartx.putIfAbsent](dart.str`${actualTypeName} <${src}>`, dart.fn(() => new dart._MethodStats(core.String._check(actualTypeName), src), VoidTo_MethodStats()));
+    o.count = dart.notNull(o.count) + 1;
   };
   dart._callMethod = function(obj, name, typeArgs, args, displayName) {
     let symbol = dart._canonicalMember(obj, name);
@@ -2437,9 +2437,25 @@
     statics: () => ({_namedArgsToSymbols: dart.definiteFunctionType(core.Map$(core.Symbol, dart.dynamic), [dart.dynamic])}),
     names: ['_namedArgsToSymbols']
   });
+  dart._MethodStats = class _MethodStats extends core.Object {
+    new(typeName, frame) {
+      this.typeName = typeName;
+      this.frame = frame;
+      this.count = null;
+      this.count = 0;
+    }
+  };
+  dart.setSignature(dart._MethodStats, {
+    constructors: () => ({new: dart.definiteFunctionType(dart._MethodStats, [core.String, core.String])}),
+    fields: () => ({
+      typeName: core.String,
+      frame: core.String,
+      count: core.int
+    })
+  });
   dart.defineLazy(dart, {
     get _callMethodStats() {
-      return MapOfString$int().new();
+      return MapOfString$_MethodStats().new();
     },
     set _callMethodStats(_) {}
   });
@@ -3599,12 +3615,12 @@
     let VoidToE = () => (VoidToE = dart.constFn(dart.functionType(E, [])))();
     let ListOfE = () => (ListOfE = dart.constFn(core.List$(E)))();
     let ReversedListIterableOfE = () => (ReversedListIterableOfE = dart.constFn(_internal.ReversedListIterable$(E)))();
-    let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
     let SetOfE = () => (SetOfE = dart.constFn(core.Set$(E)))();
     let ArrayIteratorOfE = () => (ArrayIteratorOfE = dart.constFn(_interceptors.ArrayIterator$(E)))();
     let ListMapViewOfE = () => (ListMapViewOfE = dart.constFn(_internal.ListMapView$(E)))();
     let ETobool = () => (ETobool = dart.constFn(dart.functionType(core.bool, [E])))();
     let ETovoid = () => (ETovoid = dart.constFn(dart.functionType(dart.void, [E])))();
+    let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
     dart.defineExtensionNames([
       'checkMutable',
       'checkGrowable',
@@ -4044,7 +4060,11 @@
       [dartx.sort](compare) {
         if (compare === void 0) compare = null;
         this[dartx.checkMutable]('sort');
-        _internal.Sort.sort(E)(this, EAndEToint()._check(compare == null ? core.Comparable.compare : compare));
+        if (compare == null) {
+          _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
+        } else {
+          _internal.Sort.sort(E)(this, compare);
+        }
       }
       [dartx.shuffle](random) {
         if (random === void 0) random = null;
@@ -5750,7 +5770,7 @@
       sort(compare) {
         if (compare === void 0) compare = null;
         if (compare == null) {
-          _internal.Sort.sort(core.Comparable)(this, core.Comparable.compare);
+          _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
         } else {
           _internal.Sort.sort(E)(this, compare);
         }
@@ -10604,7 +10624,7 @@
     }
     serializeMap(x) {
       let serializeTearOff = dart.bind(this, 'serialize');
-      return JSArrayOfObject().of(['map', x[dartx.keys][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x[dartx.values][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
+      return JSArrayOfObject().of(['map', x.keys[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x.values[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
     }
     serializeJSObject(x) {
       if (!!x.constructor && x.constructor !== Object) {
@@ -10666,7 +10686,7 @@
       serializeJSIndexable: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSIndexable]),
       serializeArray: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
       serializeArrayInPlace: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
-      serializeMap: dart.definiteFunctionType(dart.dynamic, [core.Map]),
+      serializeMap: dart.definiteFunctionType(dart.dynamic, [_js_helper.InternalMap]),
       serializeJSObject: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSObject]),
       serializeWorkerSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._WorkerSendPort]),
       serializeJsSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._NativeJsSendPort]),
@@ -10716,7 +10736,7 @@
         }
         case "map":
         {
-          return this.deserializeMap(x);
+          return this.deserializeMap(_js_helper.InternalMap._check(x));
         }
         case "sendport":
         {
@@ -10798,9 +10818,9 @@
       return _interceptors.JSArray.markFixed(this.deserializeArrayInPlace(_interceptors.JSArray._check(result)));
     }
     deserializeMap(x) {
-      dart.assert(dart.equals(dart.dindex(x, 0), 'map'));
-      let keys = core.List._check(dart.dindex(x, 1));
-      let values = core.List._check(dart.dindex(x, 2));
+      dart.assert(dart.equals(x.get(0), 'map'));
+      let keys = core.List._check(x.get(1));
+      let values = core.List._check(x.get(2));
       let result = dart.map();
       this.deserializedObjects[dartx.add](result);
       keys = keys[dartx.map](dart.dynamic)(dart.bind(this, 'deserialize'))[dartx.toList]();
@@ -10881,7 +10901,7 @@
       deserializeExtendable: dart.definiteFunctionType(core.List, [dart.dynamic]),
       deserializeMutable: dart.definiteFunctionType(core.List, [dart.dynamic]),
       deserializeConst: dart.definiteFunctionType(core.List, [dart.dynamic]),
-      deserializeMap: dart.definiteFunctionType(core.Map, [dart.dynamic]),
+      deserializeMap: dart.definiteFunctionType(core.Map, [_js_helper.InternalMap]),
       deserializeSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
       deserializeRawSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
       deserializeJSObject: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
@@ -10928,7 +10948,14 @@
     constructors: () => ({new: dart.definiteFunctionType(_js_helper._Patch, [])})
   });
   _js_helper.patch = dart.const(new _js_helper._Patch());
-  _js_helper.InternalMap = class InternalMap extends core.Object {};
+  _js_helper.InternalMap$ = dart.generic((K, V) => {
+    let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
+    class InternalMap extends core.Object {}
+    dart.addTypeTests(InternalMap);
+    InternalMap[dart.implements] = () => [MapOfK$V()];
+    return InternalMap;
+  });
+  _js_helper.InternalMap = InternalMap();
   _js_helper.Primitives = class Primitives extends core.Object {
     static initializeStatics(id) {
       _js_helper.Primitives.mirrorFunctionCacheName = dart.notNull(_js_helper.Primitives.mirrorFunctionCacheName) + dart.str`_${id}`;
@@ -11850,6 +11877,7 @@
     let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
     let LinkedHashMapCellOfK$V = () => (LinkedHashMapCellOfK$V = dart.constFn(_js_helper.LinkedHashMapCell$(K, V)))();
     let LinkedHashMapOfK$V = () => (LinkedHashMapOfK$V = dart.constFn(collection.LinkedHashMap$(K, V)))();
+    let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
     let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
     let KToV = () => (KToV = dart.constFn(dart.definiteFunctionType(V, [K])))();
     let KTobool = () => (KTobool = dart.constFn(dart.definiteFunctionType(core.bool, [K])))();
@@ -12122,7 +12150,7 @@
       }
     }
     dart.addTypeTests(JsLinkedHashMap);
-    JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), _js_helper.InternalMap];
+    JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), InternalMapOfK$V()];
     dart.setSignature(JsLinkedHashMap, {
       constructors: () => ({
         new: dart.definiteFunctionType(_js_helper.JsLinkedHashMap$(K, V), []),
@@ -23448,6 +23476,7 @@
     let _Es6MapIterableOfK = () => (_Es6MapIterableOfK = dart.constFn(collection._Es6MapIterable$(K)))();
     let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
     let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
+    let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
     let _Es6MapIterableOfV = () => (_Es6MapIterableOfV = dart.constFn(collection._Es6MapIterable$(V)))();
     let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
     let KAndVTovoid$ = () => (KAndVTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [K, V])))();
@@ -23536,7 +23565,7 @@
         return collection.Maps.mapToString(this);
       }
     }
-    _Es6LinkedIdentityHashMap[dart.implements] = () => [_js_helper.InternalMap];
+    _Es6LinkedIdentityHashMap[dart.implements] = () => [InternalMapOfK$V()];
     dart.setSignature(_Es6LinkedIdentityHashMap, {
       constructors: () => ({new: dart.definiteFunctionType(collection._Es6LinkedIdentityHashMap$(K, V), [])}),
       fields: () => ({
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index 469de00..f8258be 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -34,7 +34,7 @@
   let JSArrayOfListOfObject = () => (JSArrayOfListOfObject = dart.constFn(_interceptors.JSArray$(ListOfObject())))();
   let JSArrayOfObject = () => (JSArrayOfObject = dart.constFn(_interceptors.JSArray$(core.Object)))();
   let MapOfSymbol$dynamic = () => (MapOfSymbol$dynamic = dart.constFn(core.Map$(core.Symbol, dart.dynamic)))();
-  let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
+  let MapOfString$_MethodStats = () => (MapOfString$_MethodStats = dart.constFn(core.Map$(core.String, dart._MethodStats)))();
   let ListOfString = () => (ListOfString = dart.constFn(core.List$(core.String)))();
   let SetOfNameValuePair = () => (SetOfNameValuePair = dart.constFn(core.Set$(_debugger.NameValuePair)))();
   let JSArrayOfNameValuePair = () => (JSArrayOfNameValuePair = dart.constFn(_interceptors.JSArray$(_debugger.NameValuePair)))();
@@ -119,6 +119,7 @@
   let TimerTovoid = () => (TimerTovoid = dart.constFn(dart.functionType(dart.void, [async.Timer])))();
   let MapOfdynamic$int = () => (MapOfdynamic$int = dart.constFn(core.Map$(dart.dynamic, core.int)))();
   let dynamicTodynamic = () => (dynamicTodynamic = dart.constFn(dart.functionType(dart.dynamic, [dart.dynamic])))();
+  let InternalMap = () => (InternalMap = dart.constFn(_js_helper.InternalMap$()))();
   let JSArrayOfint = () => (JSArrayOfint = dart.constFn(_interceptors.JSArray$(core.int)))();
   let ListOfint = () => (ListOfint = dart.constFn(core.List$(core.int)))();
   let SyncIterator = () => (SyncIterator = dart.constFn(_js_helper.SyncIterator$()))();
@@ -513,6 +514,7 @@
   let MapOfString$Function = () => (MapOfString$Function = dart.constFn(core.Map$(core.String, core.Function)))();
   let JSArrayOfKeyEvent = () => (JSArrayOfKeyEvent = dart.constFn(_interceptors.JSArray$(html$.KeyEvent)))();
   let ListOfKeyEvent = () => (ListOfKeyEvent = dart.constFn(core.List$(html$.KeyEvent)))();
+  let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
   let JSArrayOfNodeValidator = () => (JSArrayOfNodeValidator = dart.constFn(_interceptors.JSArray$(html$.NodeValidator)))();
   let ListOfNodeValidator = () => (ListOfNodeValidator = dart.constFn(core.List$(html$.NodeValidator)))();
   let _WrappedList = () => (_WrappedList = dart.constFn(html$._WrappedList$()))();
@@ -531,6 +533,7 @@
   let CompleterOfAudioBuffer = () => (CompleterOfAudioBuffer = dart.constFn(async.Completer$(web_audio.AudioBuffer)))();
   let EventStreamProviderOfAudioProcessingEvent = () => (EventStreamProviderOfAudioProcessingEvent = dart.constFn(html$.EventStreamProvider$(web_audio.AudioProcessingEvent)))();
   let StringAndStringToint = () => (StringAndStringToint = dart.constFn(dart.definiteFunctionType(core.int, [core.String, core.String])))();
+  let VoidTo_MethodStats = () => (VoidTo_MethodStats = dart.constFn(dart.definiteFunctionType(dart._MethodStats, [])))();
   let dynamicTodynamic$ = () => (dynamicTodynamic$ = dart.constFn(dart.definiteFunctionType(dart.dynamic, [dart.dynamic])))();
   let dynamicToString = () => (dynamicToString = dart.constFn(dart.definiteFunctionType(core.String, [dart.dynamic])))();
   let dynamicToListOfString = () => (dynamicToListOfString = dart.constFn(dart.definiteFunctionType(ListOfString(), [dart.dynamic])))();
@@ -560,6 +563,7 @@
   let FunctionTovoid = () => (FunctionTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Function])))();
   let StringAndStringToString$ = () => (StringAndStringToString$ = dart.constFn(dart.definiteFunctionType(core.String, [core.String, core.String])))();
   let TypeAndStringTodynamic = () => (TypeAndStringTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [core.Type, core.String])))();
+  let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
   let ListOfEToListOfE = () => (ListOfEToListOfE = dart.constFn(dart.definiteFunctionType(E => [core.List$(E), [core.List$(E)]])))();
   let StringTovoid$ = () => (StringTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [core.String])))();
   let _IsolateContextAndFunctionTodynamic = () => (_IsolateContextAndFunctionTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [_isolate_helper._IsolateContext, core.Function])))();
@@ -670,7 +674,6 @@
   let ObjectToint = () => (ObjectToint = dart.constFn(dart.definiteFunctionType(core.int, [core.Object])))();
   let ObjectTovoid = () => (ObjectTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Object])))();
   let StringAndStringTovoid$ = () => (StringAndStringTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [core.String, core.String])))();
-  let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
   let MapOfString$StringAndStringToMapOfString$String = () => (MapOfString$StringAndStringToMapOfString$String = dart.constFn(dart.definiteFunctionType(MapOfString$String(), [MapOfString$String(), core.String])))();
   let intAndintAndintTovoid = () => (intAndintAndintTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.int, core.int, core.int])))();
   let String__Tovoid = () => (String__Tovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.String], [dart.dynamic])))();
@@ -1448,7 +1451,7 @@
   };
   dart.dload = function(obj, field) {
     let f = dart._canonicalMember(obj, field);
-    dart._trackCall(obj, f);
+    dart._trackCall(obj);
     if (f != null) {
       if (dart.test(dart.hasMethod(obj, f))) return dart.bind(obj, f, void 0);
       return obj[f];
@@ -1457,7 +1460,7 @@
   };
   dart.dput = function(obj, field, value) {
     let f = dart._canonicalMember(obj, field);
-    dart._trackCall(obj, f);
+    dart._trackCall(obj);
     if (f != null) {
       return obj[f] = value;
     }
@@ -1505,7 +1508,7 @@
     return null;
   };
   dart._checkAndCall = function(f, ftype, obj, typeArgs, args, name) {
-    dart._trackCall(obj, name);
+    dart._trackCall(obj);
     let originalTarget = obj === void 0 ? f : obj;
     function callNSM() {
       return dart.noSuchMethod(originalTarget, new dart.InvocationImpl(name, args, {namedArguments: dart.extractNamedArgs(args), isMethod: true}));
@@ -1556,17 +1559,17 @@
   dart.getDynamicStats = function() {
     let ret = JSArrayOfListOfObject().of([]);
     let keys = dart._callMethodStats[dartx.keys][dartx.toList]();
-    keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b)[dartx.compareTo](dart._callMethodStats[dartx.get](a)), StringAndStringToint()));
+    keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b).count[dartx.compareTo](dart._callMethodStats[dartx.get](a).count), StringAndStringToint()));
     for (let key of keys) {
-      let count = dart._callMethodStats[dartx.get](key);
-      ret[dartx.add](JSArrayOfObject().of([key, count]));
+      let stats = dart._callMethodStats[dartx.get](key);
+      ret[dartx.add](JSArrayOfObject().of([stats.typeName, stats.frame, stats.count]));
     }
     return ret;
   };
   dart.clearDynamicStats = function() {
     dart._callMethodStats[dartx.clear]();
   };
-  dart._trackCall = function(obj, name) {
+  dart._trackCall = function(obj) {
     if (!dart.trackProfile) return;
     let actual = dart.getReifiedType(obj);
     let stackStr = new Error().stack;
@@ -1579,12 +1582,9 @@
         break;
       }
     }
-    name = dart.str`${dart.typeName(actual)}.${name} <${src}>`;
-    if (dart.test(dart._callMethodStats[dartx.containsKey](name))) {
-      dart._callMethodStats[dartx.set](core.String._check(name), dart.notNull(dart._callMethodStats[dartx.get](name)) + 1);
-    } else {
-      dart._callMethodStats[dartx.set](core.String._check(name), 1);
-    }
+    let actualTypeName = dart.typeName(actual);
+    let o = dart._callMethodStats[dartx.putIfAbsent](dart.str`${actualTypeName} <${src}>`, dart.fn(() => new dart._MethodStats(core.String._check(actualTypeName), src), VoidTo_MethodStats()));
+    o.count = dart.notNull(o.count) + 1;
   };
   dart._callMethod = function(obj, name, typeArgs, args, displayName) {
     let symbol = dart._canonicalMember(obj, name);
@@ -2437,9 +2437,25 @@
     statics: () => ({_namedArgsToSymbols: dart.definiteFunctionType(core.Map$(core.Symbol, dart.dynamic), [dart.dynamic])}),
     names: ['_namedArgsToSymbols']
   });
+  dart._MethodStats = class _MethodStats extends core.Object {
+    new(typeName, frame) {
+      this.typeName = typeName;
+      this.frame = frame;
+      this.count = null;
+      this.count = 0;
+    }
+  };
+  dart.setSignature(dart._MethodStats, {
+    constructors: () => ({new: dart.definiteFunctionType(dart._MethodStats, [core.String, core.String])}),
+    fields: () => ({
+      typeName: core.String,
+      frame: core.String,
+      count: core.int
+    })
+  });
   dart.defineLazy(dart, {
     get _callMethodStats() {
-      return MapOfString$int().new();
+      return MapOfString$_MethodStats().new();
     },
     set _callMethodStats(_) {}
   });
@@ -3599,12 +3615,12 @@
     let VoidToE = () => (VoidToE = dart.constFn(dart.functionType(E, [])))();
     let ListOfE = () => (ListOfE = dart.constFn(core.List$(E)))();
     let ReversedListIterableOfE = () => (ReversedListIterableOfE = dart.constFn(_internal.ReversedListIterable$(E)))();
-    let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
     let SetOfE = () => (SetOfE = dart.constFn(core.Set$(E)))();
     let ArrayIteratorOfE = () => (ArrayIteratorOfE = dart.constFn(_interceptors.ArrayIterator$(E)))();
     let ListMapViewOfE = () => (ListMapViewOfE = dart.constFn(_internal.ListMapView$(E)))();
     let ETobool = () => (ETobool = dart.constFn(dart.functionType(core.bool, [E])))();
     let ETovoid = () => (ETovoid = dart.constFn(dart.functionType(dart.void, [E])))();
+    let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
     dart.defineExtensionNames([
       'checkMutable',
       'checkGrowable',
@@ -4044,7 +4060,11 @@
       [dartx.sort](compare) {
         if (compare === void 0) compare = null;
         this[dartx.checkMutable]('sort');
-        _internal.Sort.sort(E)(this, EAndEToint()._check(compare == null ? core.Comparable.compare : compare));
+        if (compare == null) {
+          _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
+        } else {
+          _internal.Sort.sort(E)(this, compare);
+        }
       }
       [dartx.shuffle](random) {
         if (random === void 0) random = null;
@@ -5750,7 +5770,7 @@
       sort(compare) {
         if (compare === void 0) compare = null;
         if (compare == null) {
-          _internal.Sort.sort(core.Comparable)(this, core.Comparable.compare);
+          _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
         } else {
           _internal.Sort.sort(E)(this, compare);
         }
@@ -10604,7 +10624,7 @@
     }
     serializeMap(x) {
       let serializeTearOff = dart.bind(this, 'serialize');
-      return JSArrayOfObject().of(['map', x[dartx.keys][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x[dartx.values][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
+      return JSArrayOfObject().of(['map', x.keys[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x.values[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
     }
     serializeJSObject(x) {
       if (!!x.constructor && x.constructor !== Object) {
@@ -10666,7 +10686,7 @@
       serializeJSIndexable: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSIndexable]),
       serializeArray: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
       serializeArrayInPlace: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
-      serializeMap: dart.definiteFunctionType(dart.dynamic, [core.Map]),
+      serializeMap: dart.definiteFunctionType(dart.dynamic, [_js_helper.InternalMap]),
       serializeJSObject: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSObject]),
       serializeWorkerSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._WorkerSendPort]),
       serializeJsSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._NativeJsSendPort]),
@@ -10716,7 +10736,7 @@
         }
         case "map":
         {
-          return this.deserializeMap(x);
+          return this.deserializeMap(_js_helper.InternalMap._check(x));
         }
         case "sendport":
         {
@@ -10798,9 +10818,9 @@
       return _interceptors.JSArray.markFixed(this.deserializeArrayInPlace(_interceptors.JSArray._check(result)));
     }
     deserializeMap(x) {
-      dart.assert(dart.equals(dart.dindex(x, 0), 'map'));
-      let keys = core.List._check(dart.dindex(x, 1));
-      let values = core.List._check(dart.dindex(x, 2));
+      dart.assert(dart.equals(x.get(0), 'map'));
+      let keys = core.List._check(x.get(1));
+      let values = core.List._check(x.get(2));
       let result = dart.map();
       this.deserializedObjects[dartx.add](result);
       keys = keys[dartx.map](dart.dynamic)(dart.bind(this, 'deserialize'))[dartx.toList]();
@@ -10881,7 +10901,7 @@
       deserializeExtendable: dart.definiteFunctionType(core.List, [dart.dynamic]),
       deserializeMutable: dart.definiteFunctionType(core.List, [dart.dynamic]),
       deserializeConst: dart.definiteFunctionType(core.List, [dart.dynamic]),
-      deserializeMap: dart.definiteFunctionType(core.Map, [dart.dynamic]),
+      deserializeMap: dart.definiteFunctionType(core.Map, [_js_helper.InternalMap]),
       deserializeSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
       deserializeRawSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
       deserializeJSObject: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
@@ -10928,7 +10948,14 @@
     constructors: () => ({new: dart.definiteFunctionType(_js_helper._Patch, [])})
   });
   _js_helper.patch = dart.const(new _js_helper._Patch());
-  _js_helper.InternalMap = class InternalMap extends core.Object {};
+  _js_helper.InternalMap$ = dart.generic((K, V) => {
+    let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
+    class InternalMap extends core.Object {}
+    dart.addTypeTests(InternalMap);
+    InternalMap[dart.implements] = () => [MapOfK$V()];
+    return InternalMap;
+  });
+  _js_helper.InternalMap = InternalMap();
   _js_helper.Primitives = class Primitives extends core.Object {
     static initializeStatics(id) {
       _js_helper.Primitives.mirrorFunctionCacheName = dart.notNull(_js_helper.Primitives.mirrorFunctionCacheName) + dart.str`_${id}`;
@@ -11850,6 +11877,7 @@
     let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
     let LinkedHashMapCellOfK$V = () => (LinkedHashMapCellOfK$V = dart.constFn(_js_helper.LinkedHashMapCell$(K, V)))();
     let LinkedHashMapOfK$V = () => (LinkedHashMapOfK$V = dart.constFn(collection.LinkedHashMap$(K, V)))();
+    let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
     let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
     let KToV = () => (KToV = dart.constFn(dart.definiteFunctionType(V, [K])))();
     let KTobool = () => (KTobool = dart.constFn(dart.definiteFunctionType(core.bool, [K])))();
@@ -12122,7 +12150,7 @@
       }
     }
     dart.addTypeTests(JsLinkedHashMap);
-    JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), _js_helper.InternalMap];
+    JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), InternalMapOfK$V()];
     dart.setSignature(JsLinkedHashMap, {
       constructors: () => ({
         new: dart.definiteFunctionType(_js_helper.JsLinkedHashMap$(K, V), []),
@@ -23448,6 +23476,7 @@
     let _Es6MapIterableOfK = () => (_Es6MapIterableOfK = dart.constFn(collection._Es6MapIterable$(K)))();
     let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
     let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
+    let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
     let _Es6MapIterableOfV = () => (_Es6MapIterableOfV = dart.constFn(collection._Es6MapIterable$(V)))();
     let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
     let KAndVTovoid$ = () => (KAndVTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [K, V])))();
@@ -23536,7 +23565,7 @@
         return collection.Maps.mapToString(this);
       }
     }
-    _Es6LinkedIdentityHashMap[dart.implements] = () => [_js_helper.InternalMap];
+    _Es6LinkedIdentityHashMap[dart.implements] = () => [InternalMapOfK$V()];
     dart.setSignature(_Es6LinkedIdentityHashMap, {
       constructors: () => ({new: dart.definiteFunctionType(collection._Es6LinkedIdentityHashMap$(K, V), [])}),
       fields: () => ({
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index 40de817..c37bee4 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -32,7 +32,7 @@
 let JSArrayOfListOfObject = () => (JSArrayOfListOfObject = dart.constFn(_interceptors.JSArray$(ListOfObject())))();
 let JSArrayOfObject = () => (JSArrayOfObject = dart.constFn(_interceptors.JSArray$(core.Object)))();
 let MapOfSymbol$dynamic = () => (MapOfSymbol$dynamic = dart.constFn(core.Map$(core.Symbol, dart.dynamic)))();
-let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
+let MapOfString$_MethodStats = () => (MapOfString$_MethodStats = dart.constFn(core.Map$(core.String, dart._MethodStats)))();
 let ListOfString = () => (ListOfString = dart.constFn(core.List$(core.String)))();
 let SetOfNameValuePair = () => (SetOfNameValuePair = dart.constFn(core.Set$(_debugger.NameValuePair)))();
 let JSArrayOfNameValuePair = () => (JSArrayOfNameValuePair = dart.constFn(_interceptors.JSArray$(_debugger.NameValuePair)))();
@@ -117,6 +117,7 @@
 let TimerTovoid = () => (TimerTovoid = dart.constFn(dart.functionType(dart.void, [async.Timer])))();
 let MapOfdynamic$int = () => (MapOfdynamic$int = dart.constFn(core.Map$(dart.dynamic, core.int)))();
 let dynamicTodynamic = () => (dynamicTodynamic = dart.constFn(dart.functionType(dart.dynamic, [dart.dynamic])))();
+let InternalMap = () => (InternalMap = dart.constFn(_js_helper.InternalMap$()))();
 let JSArrayOfint = () => (JSArrayOfint = dart.constFn(_interceptors.JSArray$(core.int)))();
 let ListOfint = () => (ListOfint = dart.constFn(core.List$(core.int)))();
 let SyncIterator = () => (SyncIterator = dart.constFn(_js_helper.SyncIterator$()))();
@@ -511,6 +512,7 @@
 let MapOfString$Function = () => (MapOfString$Function = dart.constFn(core.Map$(core.String, core.Function)))();
 let JSArrayOfKeyEvent = () => (JSArrayOfKeyEvent = dart.constFn(_interceptors.JSArray$(html.KeyEvent)))();
 let ListOfKeyEvent = () => (ListOfKeyEvent = dart.constFn(core.List$(html.KeyEvent)))();
+let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
 let JSArrayOfNodeValidator = () => (JSArrayOfNodeValidator = dart.constFn(_interceptors.JSArray$(html.NodeValidator)))();
 let ListOfNodeValidator = () => (ListOfNodeValidator = dart.constFn(core.List$(html.NodeValidator)))();
 let _WrappedList = () => (_WrappedList = dart.constFn(html._WrappedList$()))();
@@ -529,6 +531,7 @@
 let CompleterOfAudioBuffer = () => (CompleterOfAudioBuffer = dart.constFn(async.Completer$(web_audio.AudioBuffer)))();
 let EventStreamProviderOfAudioProcessingEvent = () => (EventStreamProviderOfAudioProcessingEvent = dart.constFn(html.EventStreamProvider$(web_audio.AudioProcessingEvent)))();
 let StringAndStringToint = () => (StringAndStringToint = dart.constFn(dart.definiteFunctionType(core.int, [core.String, core.String])))();
+let VoidTo_MethodStats = () => (VoidTo_MethodStats = dart.constFn(dart.definiteFunctionType(dart._MethodStats, [])))();
 let dynamicTodynamic = () => (dynamicTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [dart.dynamic])))();
 let dynamicToString = () => (dynamicToString = dart.constFn(dart.definiteFunctionType(core.String, [dart.dynamic])))();
 let dynamicToListOfString = () => (dynamicToListOfString = dart.constFn(dart.definiteFunctionType(ListOfString(), [dart.dynamic])))();
@@ -558,6 +561,7 @@
 let FunctionTovoid = () => (FunctionTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Function])))();
 let StringAndStringToString = () => (StringAndStringToString = dart.constFn(dart.definiteFunctionType(core.String, [core.String, core.String])))();
 let TypeAndStringTodynamic = () => (TypeAndStringTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [core.Type, core.String])))();
+let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
 let ListOfEToListOfE = () => (ListOfEToListOfE = dart.constFn(dart.definiteFunctionType(E => [core.List$(E), [core.List$(E)]])))();
 let StringTovoid = () => (StringTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.String])))();
 let _IsolateContextAndFunctionTodynamic = () => (_IsolateContextAndFunctionTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [_isolate_helper._IsolateContext, core.Function])))();
@@ -668,7 +672,6 @@
 let ObjectToint = () => (ObjectToint = dart.constFn(dart.definiteFunctionType(core.int, [core.Object])))();
 let ObjectTovoid = () => (ObjectTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Object])))();
 let StringAndStringTovoid = () => (StringAndStringTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.String, core.String])))();
-let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
 let MapOfString$StringAndStringToMapOfString$String = () => (MapOfString$StringAndStringToMapOfString$String = dart.constFn(dart.definiteFunctionType(MapOfString$String(), [MapOfString$String(), core.String])))();
 let intAndintAndintTovoid = () => (intAndintAndintTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.int, core.int, core.int])))();
 let String__Tovoid = () => (String__Tovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.String], [dart.dynamic])))();
@@ -1446,7 +1449,7 @@
 };
 dart.dload = function(obj, field) {
   let f = dart._canonicalMember(obj, field);
-  dart._trackCall(obj, f);
+  dart._trackCall(obj);
   if (f != null) {
     if (dart.test(dart.hasMethod(obj, f))) return dart.bind(obj, f, void 0);
     return obj[f];
@@ -1455,7 +1458,7 @@
 };
 dart.dput = function(obj, field, value) {
   let f = dart._canonicalMember(obj, field);
-  dart._trackCall(obj, f);
+  dart._trackCall(obj);
   if (f != null) {
     return obj[f] = value;
   }
@@ -1503,7 +1506,7 @@
   return null;
 };
 dart._checkAndCall = function(f, ftype, obj, typeArgs, args, name) {
-  dart._trackCall(obj, name);
+  dart._trackCall(obj);
   let originalTarget = obj === void 0 ? f : obj;
   function callNSM() {
     return dart.noSuchMethod(originalTarget, new dart.InvocationImpl(name, args, {namedArguments: dart.extractNamedArgs(args), isMethod: true}));
@@ -1554,17 +1557,17 @@
 dart.getDynamicStats = function() {
   let ret = JSArrayOfListOfObject().of([]);
   let keys = dart._callMethodStats[dartx.keys][dartx.toList]();
-  keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b)[dartx.compareTo](dart._callMethodStats[dartx.get](a)), StringAndStringToint()));
+  keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b).count[dartx.compareTo](dart._callMethodStats[dartx.get](a).count), StringAndStringToint()));
   for (let key of keys) {
-    let count = dart._callMethodStats[dartx.get](key);
-    ret[dartx.add](JSArrayOfObject().of([key, count]));
+    let stats = dart._callMethodStats[dartx.get](key);
+    ret[dartx.add](JSArrayOfObject().of([stats.typeName, stats.frame, stats.count]));
   }
   return ret;
 };
 dart.clearDynamicStats = function() {
   dart._callMethodStats[dartx.clear]();
 };
-dart._trackCall = function(obj, name) {
+dart._trackCall = function(obj) {
   if (!dart.trackProfile) return;
   let actual = dart.getReifiedType(obj);
   let stackStr = new Error().stack;
@@ -1577,12 +1580,9 @@
       break;
     }
   }
-  name = dart.str`${dart.typeName(actual)}.${name} <${src}>`;
-  if (dart.test(dart._callMethodStats[dartx.containsKey](name))) {
-    dart._callMethodStats[dartx.set](core.String._check(name), dart.notNull(dart._callMethodStats[dartx.get](name)) + 1);
-  } else {
-    dart._callMethodStats[dartx.set](core.String._check(name), 1);
-  }
+  let actualTypeName = dart.typeName(actual);
+  let o = dart._callMethodStats[dartx.putIfAbsent](dart.str`${actualTypeName} <${src}>`, dart.fn(() => new dart._MethodStats(core.String._check(actualTypeName), src), VoidTo_MethodStats()));
+  o.count = dart.notNull(o.count) + 1;
 };
 dart._callMethod = function(obj, name, typeArgs, args, displayName) {
   let symbol = dart._canonicalMember(obj, name);
@@ -2435,9 +2435,25 @@
   statics: () => ({_namedArgsToSymbols: dart.definiteFunctionType(core.Map$(core.Symbol, dart.dynamic), [dart.dynamic])}),
   names: ['_namedArgsToSymbols']
 });
+dart._MethodStats = class _MethodStats extends core.Object {
+  new(typeName, frame) {
+    this.typeName = typeName;
+    this.frame = frame;
+    this.count = null;
+    this.count = 0;
+  }
+};
+dart.setSignature(dart._MethodStats, {
+  constructors: () => ({new: dart.definiteFunctionType(dart._MethodStats, [core.String, core.String])}),
+  fields: () => ({
+    typeName: core.String,
+    frame: core.String,
+    count: core.int
+  })
+});
 dart.defineLazy(dart, {
   get _callMethodStats() {
-    return MapOfString$int().new();
+    return MapOfString$_MethodStats().new();
   },
   set _callMethodStats(_) {}
 });
@@ -3597,12 +3613,12 @@
   let VoidToE = () => (VoidToE = dart.constFn(dart.functionType(E, [])))();
   let ListOfE = () => (ListOfE = dart.constFn(core.List$(E)))();
   let ReversedListIterableOfE = () => (ReversedListIterableOfE = dart.constFn(_internal.ReversedListIterable$(E)))();
-  let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
   let SetOfE = () => (SetOfE = dart.constFn(core.Set$(E)))();
   let ArrayIteratorOfE = () => (ArrayIteratorOfE = dart.constFn(_interceptors.ArrayIterator$(E)))();
   let ListMapViewOfE = () => (ListMapViewOfE = dart.constFn(_internal.ListMapView$(E)))();
   let ETobool = () => (ETobool = dart.constFn(dart.functionType(core.bool, [E])))();
   let ETovoid = () => (ETovoid = dart.constFn(dart.functionType(dart.void, [E])))();
+  let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
   dart.defineExtensionNames([
     'checkMutable',
     'checkGrowable',
@@ -4042,7 +4058,11 @@
     [dartx.sort](compare) {
       if (compare === void 0) compare = null;
       this[dartx.checkMutable]('sort');
-      _internal.Sort.sort(E)(this, EAndEToint()._check(compare == null ? core.Comparable.compare : compare));
+      if (compare == null) {
+        _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
+      } else {
+        _internal.Sort.sort(E)(this, compare);
+      }
     }
     [dartx.shuffle](random) {
       if (random === void 0) random = null;
@@ -5748,7 +5768,7 @@
     sort(compare) {
       if (compare === void 0) compare = null;
       if (compare == null) {
-        _internal.Sort.sort(core.Comparable)(this, core.Comparable.compare);
+        _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
       } else {
         _internal.Sort.sort(E)(this, compare);
       }
@@ -10602,7 +10622,7 @@
   }
   serializeMap(x) {
     let serializeTearOff = dart.bind(this, 'serialize');
-    return JSArrayOfObject().of(['map', x[dartx.keys][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x[dartx.values][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
+    return JSArrayOfObject().of(['map', x.keys[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x.values[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
   }
   serializeJSObject(x) {
     if (!!x.constructor && x.constructor !== Object) {
@@ -10664,7 +10684,7 @@
     serializeJSIndexable: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSIndexable]),
     serializeArray: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
     serializeArrayInPlace: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
-    serializeMap: dart.definiteFunctionType(dart.dynamic, [core.Map]),
+    serializeMap: dart.definiteFunctionType(dart.dynamic, [_js_helper.InternalMap]),
     serializeJSObject: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSObject]),
     serializeWorkerSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._WorkerSendPort]),
     serializeJsSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._NativeJsSendPort]),
@@ -10714,7 +10734,7 @@
       }
       case "map":
       {
-        return this.deserializeMap(x);
+        return this.deserializeMap(_js_helper.InternalMap._check(x));
       }
       case "sendport":
       {
@@ -10796,9 +10816,9 @@
     return _interceptors.JSArray.markFixed(this.deserializeArrayInPlace(_interceptors.JSArray._check(result)));
   }
   deserializeMap(x) {
-    dart.assert(dart.equals(dart.dindex(x, 0), 'map'));
-    let keys = core.List._check(dart.dindex(x, 1));
-    let values = core.List._check(dart.dindex(x, 2));
+    dart.assert(dart.equals(x.get(0), 'map'));
+    let keys = core.List._check(x.get(1));
+    let values = core.List._check(x.get(2));
     let result = dart.map();
     this.deserializedObjects[dartx.add](result);
     keys = keys[dartx.map](dart.dynamic)(dart.bind(this, 'deserialize'))[dartx.toList]();
@@ -10879,7 +10899,7 @@
     deserializeExtendable: dart.definiteFunctionType(core.List, [dart.dynamic]),
     deserializeMutable: dart.definiteFunctionType(core.List, [dart.dynamic]),
     deserializeConst: dart.definiteFunctionType(core.List, [dart.dynamic]),
-    deserializeMap: dart.definiteFunctionType(core.Map, [dart.dynamic]),
+    deserializeMap: dart.definiteFunctionType(core.Map, [_js_helper.InternalMap]),
     deserializeSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
     deserializeRawSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
     deserializeJSObject: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
@@ -10926,7 +10946,14 @@
   constructors: () => ({new: dart.definiteFunctionType(_js_helper._Patch, [])})
 });
 _js_helper.patch = dart.const(new _js_helper._Patch());
-_js_helper.InternalMap = class InternalMap extends core.Object {};
+_js_helper.InternalMap$ = dart.generic((K, V) => {
+  let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
+  class InternalMap extends core.Object {}
+  dart.addTypeTests(InternalMap);
+  InternalMap[dart.implements] = () => [MapOfK$V()];
+  return InternalMap;
+});
+_js_helper.InternalMap = InternalMap();
 _js_helper.Primitives = class Primitives extends core.Object {
   static initializeStatics(id) {
     _js_helper.Primitives.mirrorFunctionCacheName = dart.notNull(_js_helper.Primitives.mirrorFunctionCacheName) + dart.str`_${id}`;
@@ -11848,6 +11875,7 @@
   let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
   let LinkedHashMapCellOfK$V = () => (LinkedHashMapCellOfK$V = dart.constFn(_js_helper.LinkedHashMapCell$(K, V)))();
   let LinkedHashMapOfK$V = () => (LinkedHashMapOfK$V = dart.constFn(collection.LinkedHashMap$(K, V)))();
+  let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
   let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
   let KToV = () => (KToV = dart.constFn(dart.definiteFunctionType(V, [K])))();
   let KTobool = () => (KTobool = dart.constFn(dart.definiteFunctionType(core.bool, [K])))();
@@ -12120,7 +12148,7 @@
     }
   }
   dart.addTypeTests(JsLinkedHashMap);
-  JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), _js_helper.InternalMap];
+  JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), InternalMapOfK$V()];
   dart.setSignature(JsLinkedHashMap, {
     constructors: () => ({
       new: dart.definiteFunctionType(_js_helper.JsLinkedHashMap$(K, V), []),
@@ -23446,6 +23474,7 @@
   let _Es6MapIterableOfK = () => (_Es6MapIterableOfK = dart.constFn(collection._Es6MapIterable$(K)))();
   let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
   let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
+  let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
   let _Es6MapIterableOfV = () => (_Es6MapIterableOfV = dart.constFn(collection._Es6MapIterable$(V)))();
   let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
   let KAndVTovoid$ = () => (KAndVTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [K, V])))();
@@ -23534,7 +23563,7 @@
       return collection.Maps.mapToString(this);
     }
   }
-  _Es6LinkedIdentityHashMap[dart.implements] = () => [_js_helper.InternalMap];
+  _Es6LinkedIdentityHashMap[dart.implements] = () => [InternalMapOfK$V()];
   dart.setSignature(_Es6LinkedIdentityHashMap, {
     constructors: () => ({new: dart.definiteFunctionType(collection._Es6LinkedIdentityHashMap$(K, V), [])}),
     fields: () => ({
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index 1736862..a4d975f 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -35,7 +35,7 @@
   let JSArrayOfListOfObject = () => (JSArrayOfListOfObject = dart.constFn(_interceptors.JSArray$(ListOfObject())))();
   let JSArrayOfObject = () => (JSArrayOfObject = dart.constFn(_interceptors.JSArray$(core.Object)))();
   let MapOfSymbol$dynamic = () => (MapOfSymbol$dynamic = dart.constFn(core.Map$(core.Symbol, dart.dynamic)))();
-  let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
+  let MapOfString$_MethodStats = () => (MapOfString$_MethodStats = dart.constFn(core.Map$(core.String, dart._MethodStats)))();
   let ListOfString = () => (ListOfString = dart.constFn(core.List$(core.String)))();
   let SetOfNameValuePair = () => (SetOfNameValuePair = dart.constFn(core.Set$(_debugger.NameValuePair)))();
   let JSArrayOfNameValuePair = () => (JSArrayOfNameValuePair = dart.constFn(_interceptors.JSArray$(_debugger.NameValuePair)))();
@@ -120,6 +120,7 @@
   let TimerTovoid = () => (TimerTovoid = dart.constFn(dart.functionType(dart.void, [async.Timer])))();
   let MapOfdynamic$int = () => (MapOfdynamic$int = dart.constFn(core.Map$(dart.dynamic, core.int)))();
   let dynamicTodynamic = () => (dynamicTodynamic = dart.constFn(dart.functionType(dart.dynamic, [dart.dynamic])))();
+  let InternalMap = () => (InternalMap = dart.constFn(_js_helper.InternalMap$()))();
   let JSArrayOfint = () => (JSArrayOfint = dart.constFn(_interceptors.JSArray$(core.int)))();
   let ListOfint = () => (ListOfint = dart.constFn(core.List$(core.int)))();
   let SyncIterator = () => (SyncIterator = dart.constFn(_js_helper.SyncIterator$()))();
@@ -514,6 +515,7 @@
   let MapOfString$Function = () => (MapOfString$Function = dart.constFn(core.Map$(core.String, core.Function)))();
   let JSArrayOfKeyEvent = () => (JSArrayOfKeyEvent = dart.constFn(_interceptors.JSArray$(html$.KeyEvent)))();
   let ListOfKeyEvent = () => (ListOfKeyEvent = dart.constFn(core.List$(html$.KeyEvent)))();
+  let MapOfString$int = () => (MapOfString$int = dart.constFn(core.Map$(core.String, core.int)))();
   let JSArrayOfNodeValidator = () => (JSArrayOfNodeValidator = dart.constFn(_interceptors.JSArray$(html$.NodeValidator)))();
   let ListOfNodeValidator = () => (ListOfNodeValidator = dart.constFn(core.List$(html$.NodeValidator)))();
   let _WrappedList = () => (_WrappedList = dart.constFn(html$._WrappedList$()))();
@@ -532,6 +534,7 @@
   let CompleterOfAudioBuffer = () => (CompleterOfAudioBuffer = dart.constFn(async.Completer$(web_audio.AudioBuffer)))();
   let EventStreamProviderOfAudioProcessingEvent = () => (EventStreamProviderOfAudioProcessingEvent = dart.constFn(html$.EventStreamProvider$(web_audio.AudioProcessingEvent)))();
   let StringAndStringToint = () => (StringAndStringToint = dart.constFn(dart.definiteFunctionType(core.int, [core.String, core.String])))();
+  let VoidTo_MethodStats = () => (VoidTo_MethodStats = dart.constFn(dart.definiteFunctionType(dart._MethodStats, [])))();
   let dynamicTodynamic$ = () => (dynamicTodynamic$ = dart.constFn(dart.definiteFunctionType(dart.dynamic, [dart.dynamic])))();
   let dynamicToString = () => (dynamicToString = dart.constFn(dart.definiteFunctionType(core.String, [dart.dynamic])))();
   let dynamicToListOfString = () => (dynamicToListOfString = dart.constFn(dart.definiteFunctionType(ListOfString(), [dart.dynamic])))();
@@ -561,6 +564,7 @@
   let FunctionTovoid = () => (FunctionTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Function])))();
   let StringAndStringToString$ = () => (StringAndStringToString$ = dart.constFn(dart.definiteFunctionType(core.String, [core.String, core.String])))();
   let TypeAndStringTodynamic = () => (TypeAndStringTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [core.Type, core.String])))();
+  let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
   let ListOfEToListOfE = () => (ListOfEToListOfE = dart.constFn(dart.definiteFunctionType(E => [core.List$(E), [core.List$(E)]])))();
   let StringTovoid$ = () => (StringTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [core.String])))();
   let _IsolateContextAndFunctionTodynamic = () => (_IsolateContextAndFunctionTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [_isolate_helper._IsolateContext, core.Function])))();
@@ -671,7 +675,6 @@
   let ObjectToint = () => (ObjectToint = dart.constFn(dart.definiteFunctionType(core.int, [core.Object])))();
   let ObjectTovoid = () => (ObjectTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.Object])))();
   let StringAndStringTovoid$ = () => (StringAndStringTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [core.String, core.String])))();
-  let dynamicAnddynamicToint = () => (dynamicAnddynamicToint = dart.constFn(dart.definiteFunctionType(core.int, [dart.dynamic, dart.dynamic])))();
   let MapOfString$StringAndStringToMapOfString$String = () => (MapOfString$StringAndStringToMapOfString$String = dart.constFn(dart.definiteFunctionType(MapOfString$String(), [MapOfString$String(), core.String])))();
   let intAndintAndintTovoid = () => (intAndintAndintTovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.int, core.int, core.int])))();
   let String__Tovoid = () => (String__Tovoid = dart.constFn(dart.definiteFunctionType(dart.void, [core.String], [dart.dynamic])))();
@@ -1449,7 +1452,7 @@
   };
   dart.dload = function(obj, field) {
     let f = dart._canonicalMember(obj, field);
-    dart._trackCall(obj, f);
+    dart._trackCall(obj);
     if (f != null) {
       if (dart.test(dart.hasMethod(obj, f))) return dart.bind(obj, f, void 0);
       return obj[f];
@@ -1458,7 +1461,7 @@
   };
   dart.dput = function(obj, field, value) {
     let f = dart._canonicalMember(obj, field);
-    dart._trackCall(obj, f);
+    dart._trackCall(obj);
     if (f != null) {
       return obj[f] = value;
     }
@@ -1506,7 +1509,7 @@
     return null;
   };
   dart._checkAndCall = function(f, ftype, obj, typeArgs, args, name) {
-    dart._trackCall(obj, name);
+    dart._trackCall(obj);
     let originalTarget = obj === void 0 ? f : obj;
     function callNSM() {
       return dart.noSuchMethod(originalTarget, new dart.InvocationImpl(name, args, {namedArguments: dart.extractNamedArgs(args), isMethod: true}));
@@ -1557,17 +1560,17 @@
   dart.getDynamicStats = function() {
     let ret = JSArrayOfListOfObject().of([]);
     let keys = dart._callMethodStats[dartx.keys][dartx.toList]();
-    keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b)[dartx.compareTo](dart._callMethodStats[dartx.get](a)), StringAndStringToint()));
+    keys[dartx.sort](dart.fn((a, b) => dart._callMethodStats[dartx.get](b).count[dartx.compareTo](dart._callMethodStats[dartx.get](a).count), StringAndStringToint()));
     for (let key of keys) {
-      let count = dart._callMethodStats[dartx.get](key);
-      ret[dartx.add](JSArrayOfObject().of([key, count]));
+      let stats = dart._callMethodStats[dartx.get](key);
+      ret[dartx.add](JSArrayOfObject().of([stats.typeName, stats.frame, stats.count]));
     }
     return ret;
   };
   dart.clearDynamicStats = function() {
     dart._callMethodStats[dartx.clear]();
   };
-  dart._trackCall = function(obj, name) {
+  dart._trackCall = function(obj) {
     if (!dart.trackProfile) return;
     let actual = dart.getReifiedType(obj);
     let stackStr = new Error().stack;
@@ -1580,12 +1583,9 @@
         break;
       }
     }
-    name = dart.str`${dart.typeName(actual)}.${name} <${src}>`;
-    if (dart.test(dart._callMethodStats[dartx.containsKey](name))) {
-      dart._callMethodStats[dartx.set](core.String._check(name), dart.notNull(dart._callMethodStats[dartx.get](name)) + 1);
-    } else {
-      dart._callMethodStats[dartx.set](core.String._check(name), 1);
-    }
+    let actualTypeName = dart.typeName(actual);
+    let o = dart._callMethodStats[dartx.putIfAbsent](dart.str`${actualTypeName} <${src}>`, dart.fn(() => new dart._MethodStats(core.String._check(actualTypeName), src), VoidTo_MethodStats()));
+    o.count = dart.notNull(o.count) + 1;
   };
   dart._callMethod = function(obj, name, typeArgs, args, displayName) {
     let symbol = dart._canonicalMember(obj, name);
@@ -2438,9 +2438,25 @@
     statics: () => ({_namedArgsToSymbols: dart.definiteFunctionType(core.Map$(core.Symbol, dart.dynamic), [dart.dynamic])}),
     names: ['_namedArgsToSymbols']
   });
+  dart._MethodStats = class _MethodStats extends core.Object {
+    new(typeName, frame) {
+      this.typeName = typeName;
+      this.frame = frame;
+      this.count = null;
+      this.count = 0;
+    }
+  };
+  dart.setSignature(dart._MethodStats, {
+    constructors: () => ({new: dart.definiteFunctionType(dart._MethodStats, [core.String, core.String])}),
+    fields: () => ({
+      typeName: core.String,
+      frame: core.String,
+      count: core.int
+    })
+  });
   dart.defineLazy(dart, {
     get _callMethodStats() {
-      return MapOfString$int().new();
+      return MapOfString$_MethodStats().new();
     },
     set _callMethodStats(_) {}
   });
@@ -3600,12 +3616,12 @@
     let VoidToE = () => (VoidToE = dart.constFn(dart.functionType(E, [])))();
     let ListOfE = () => (ListOfE = dart.constFn(core.List$(E)))();
     let ReversedListIterableOfE = () => (ReversedListIterableOfE = dart.constFn(_internal.ReversedListIterable$(E)))();
-    let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
     let SetOfE = () => (SetOfE = dart.constFn(core.Set$(E)))();
     let ArrayIteratorOfE = () => (ArrayIteratorOfE = dart.constFn(_interceptors.ArrayIterator$(E)))();
     let ListMapViewOfE = () => (ListMapViewOfE = dart.constFn(_internal.ListMapView$(E)))();
     let ETobool = () => (ETobool = dart.constFn(dart.functionType(core.bool, [E])))();
     let ETovoid = () => (ETovoid = dart.constFn(dart.functionType(dart.void, [E])))();
+    let EAndEToint = () => (EAndEToint = dart.constFn(dart.functionType(core.int, [E, E])))();
     dart.defineExtensionNames([
       'checkMutable',
       'checkGrowable',
@@ -4045,7 +4061,11 @@
       [dartx.sort](compare) {
         if (compare === void 0) compare = null;
         this[dartx.checkMutable]('sort');
-        _internal.Sort.sort(E)(this, EAndEToint()._check(compare == null ? core.Comparable.compare : compare));
+        if (compare == null) {
+          _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
+        } else {
+          _internal.Sort.sort(E)(this, compare);
+        }
       }
       [dartx.shuffle](random) {
         if (random === void 0) random = null;
@@ -5751,7 +5771,7 @@
       sort(compare) {
         if (compare === void 0) compare = null;
         if (compare == null) {
-          _internal.Sort.sort(core.Comparable)(this, core.Comparable.compare);
+          _internal.Sort.sort(E)(this, dart.fn((a, b) => core.Comparable.compare(core.Comparable._check(a), core.Comparable._check(b)), dynamicAnddynamicToint()));
         } else {
           _internal.Sort.sort(E)(this, compare);
         }
@@ -10605,7 +10625,7 @@
     }
     serializeMap(x) {
       let serializeTearOff = dart.bind(this, 'serialize');
-      return JSArrayOfObject().of(['map', x[dartx.keys][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x[dartx.values][dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
+      return JSArrayOfObject().of(['map', x.keys[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList](), x.values[dartx.map](dart.dynamic)(dynamicTodynamic()._check(serializeTearOff))[dartx.toList]()]);
     }
     serializeJSObject(x) {
       if (!!x.constructor && x.constructor !== Object) {
@@ -10667,7 +10687,7 @@
       serializeJSIndexable: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSIndexable]),
       serializeArray: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
       serializeArrayInPlace: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSArray]),
-      serializeMap: dart.definiteFunctionType(dart.dynamic, [core.Map]),
+      serializeMap: dart.definiteFunctionType(dart.dynamic, [_js_helper.InternalMap]),
       serializeJSObject: dart.definiteFunctionType(dart.dynamic, [_interceptors.JSObject]),
       serializeWorkerSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._WorkerSendPort]),
       serializeJsSendPort: dart.definiteFunctionType(dart.dynamic, [_isolate_helper._NativeJsSendPort]),
@@ -10717,7 +10737,7 @@
         }
         case "map":
         {
-          return this.deserializeMap(x);
+          return this.deserializeMap(_js_helper.InternalMap._check(x));
         }
         case "sendport":
         {
@@ -10799,9 +10819,9 @@
       return _interceptors.JSArray.markFixed(this.deserializeArrayInPlace(_interceptors.JSArray._check(result)));
     }
     deserializeMap(x) {
-      dart.assert(dart.equals(dart.dindex(x, 0), 'map'));
-      let keys = core.List._check(dart.dindex(x, 1));
-      let values = core.List._check(dart.dindex(x, 2));
+      dart.assert(dart.equals(x.get(0), 'map'));
+      let keys = core.List._check(x.get(1));
+      let values = core.List._check(x.get(2));
       let result = dart.map();
       this.deserializedObjects[dartx.add](result);
       keys = keys[dartx.map](dart.dynamic)(dart.bind(this, 'deserialize'))[dartx.toList]();
@@ -10882,7 +10902,7 @@
       deserializeExtendable: dart.definiteFunctionType(core.List, [dart.dynamic]),
       deserializeMutable: dart.definiteFunctionType(core.List, [dart.dynamic]),
       deserializeConst: dart.definiteFunctionType(core.List, [dart.dynamic]),
-      deserializeMap: dart.definiteFunctionType(core.Map, [dart.dynamic]),
+      deserializeMap: dart.definiteFunctionType(core.Map, [_js_helper.InternalMap]),
       deserializeSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
       deserializeRawSendPort: dart.definiteFunctionType(isolate.SendPort, [dart.dynamic]),
       deserializeJSObject: dart.definiteFunctionType(dart.dynamic, [dart.dynamic]),
@@ -10929,7 +10949,14 @@
     constructors: () => ({new: dart.definiteFunctionType(_js_helper._Patch, [])})
   });
   _js_helper.patch = dart.const(new _js_helper._Patch());
-  _js_helper.InternalMap = class InternalMap extends core.Object {};
+  _js_helper.InternalMap$ = dart.generic((K, V) => {
+    let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
+    class InternalMap extends core.Object {}
+    dart.addTypeTests(InternalMap);
+    InternalMap[dart.implements] = () => [MapOfK$V()];
+    return InternalMap;
+  });
+  _js_helper.InternalMap = InternalMap();
   _js_helper.Primitives = class Primitives extends core.Object {
     static initializeStatics(id) {
       _js_helper.Primitives.mirrorFunctionCacheName = dart.notNull(_js_helper.Primitives.mirrorFunctionCacheName) + dart.str`_${id}`;
@@ -11851,6 +11878,7 @@
     let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
     let LinkedHashMapCellOfK$V = () => (LinkedHashMapCellOfK$V = dart.constFn(_js_helper.LinkedHashMapCell$(K, V)))();
     let LinkedHashMapOfK$V = () => (LinkedHashMapOfK$V = dart.constFn(collection.LinkedHashMap$(K, V)))();
+    let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
     let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
     let KToV = () => (KToV = dart.constFn(dart.definiteFunctionType(V, [K])))();
     let KTobool = () => (KTobool = dart.constFn(dart.definiteFunctionType(core.bool, [K])))();
@@ -12123,7 +12151,7 @@
       }
     }
     dart.addTypeTests(JsLinkedHashMap);
-    JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), _js_helper.InternalMap];
+    JsLinkedHashMap[dart.implements] = () => [LinkedHashMapOfK$V(), InternalMapOfK$V()];
     dart.setSignature(JsLinkedHashMap, {
       constructors: () => ({
         new: dart.definiteFunctionType(_js_helper.JsLinkedHashMap$(K, V), []),
@@ -23449,6 +23477,7 @@
     let _Es6MapIterableOfK = () => (_Es6MapIterableOfK = dart.constFn(collection._Es6MapIterable$(K)))();
     let MapOfK$V = () => (MapOfK$V = dart.constFn(core.Map$(K, V)))();
     let KAndVTovoid = () => (KAndVTovoid = dart.constFn(dart.functionType(dart.void, [K, V])))();
+    let InternalMapOfK$V = () => (InternalMapOfK$V = dart.constFn(_js_helper.InternalMap$(K, V)))();
     let _Es6MapIterableOfV = () => (_Es6MapIterableOfV = dart.constFn(collection._Es6MapIterable$(V)))();
     let VoidToV = () => (VoidToV = dart.constFn(dart.functionType(V, [])))();
     let KAndVTovoid$ = () => (KAndVTovoid$ = dart.constFn(dart.definiteFunctionType(dart.void, [K, V])))();
@@ -23537,7 +23566,7 @@
         return collection.Maps.mapToString(this);
       }
     }
-    _Es6LinkedIdentityHashMap[dart.implements] = () => [_js_helper.InternalMap];
+    _Es6LinkedIdentityHashMap[dart.implements] = () => [InternalMapOfK$V()];
     dart.setSignature(_Es6LinkedIdentityHashMap, {
       constructors: () => ({new: dart.definiteFunctionType(collection._Es6LinkedIdentityHashMap$(K, V), [])}),
       fields: () => ({
diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
index bc48e34..783e7da 100644
--- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
@@ -5095,8 +5095,7 @@
   _visit(AstNode node) {
     if (node == null) return null;
     var result = node.accept(this);
-    if (result is JS.Node) result = annotate(result, node);
-    return result;
+    return result is JS.Node ? annotate(result, node) : result;
   }
 
   List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) {
diff --git a/pkg/dev_compiler/test/codegen/language/abstract_method_test.dart b/pkg/dev_compiler/test/codegen/language/abstract_method_test.dart
index cb52fcb..c2c5225 100644
--- a/pkg/dev_compiler/test/codegen/language/abstract_method_test.dart
+++ b/pkg/dev_compiler/test/codegen/language/abstract_method_test.dart
@@ -12,7 +12,7 @@
 
 abstract class A {
   int get length;     // Abstract instance getter.
-  set height(x);      // Abstract instance setter.
+  set height(int x);  // Abstract instance setter.
   int width();        // Abstract instance method.
 
   // Must resolve to non-abstract length getter in subclass.
diff --git a/pkg/dev_compiler/test/codegen/language/field_override4_test.dart b/pkg/dev_compiler/test/codegen/language/field_override4_test.dart
index 46e6c73..a03b470 100644
--- a/pkg/dev_compiler/test/codegen/language/field_override4_test.dart
+++ b/pkg/dev_compiler/test/codegen/language/field_override4_test.dart
@@ -15,7 +15,7 @@
 }
 
 class B extends A {
-  var foo = 42;
+  dynamic foo = 42;
 }
 
 main() {
diff --git a/pkg/dev_compiler/test/codegen_test.dart b/pkg/dev_compiler/test/codegen_test.dart
index 0d1dbd92..7b3577f 100644
--- a/pkg/dev_compiler/test/codegen_test.dart
+++ b/pkg/dev_compiler/test/codegen_test.dart
@@ -26,11 +26,7 @@
 import 'package:dev_compiler/src/compiler/compiler.dart'
     show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler;
 import 'package:dev_compiler/src/compiler/module_builder.dart'
-    show
-        ModuleFormat,
-        addModuleFormatOptions,
-        parseModuleFormatOption,
-        pathToJSIdentifier;
+    show ModuleFormat, addModuleFormatOptions, parseModuleFormatOption;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart' show expect, isFalse, isTrue, test;
 
diff --git a/pkg/dev_compiler/tool/analyze.sh b/pkg/dev_compiler/tool/analyze.sh
index 40b17f4..cd457fc 100755
--- a/pkg/dev_compiler/tool/analyze.sh
+++ b/pkg/dev_compiler/tool/analyze.sh
@@ -14,7 +14,7 @@
 # repeated analysis of the same code.
 # TODO(jmesserly): ideally we could do test/all_tests.dart, but
 # dart_runtime_test.dart creates invalid generic type instantiation AA.
-echo "Running dartanalyzer to check for errors/warnings/hints..."
-dartanalyzer --strong --fatal-warnings --package-warnings \
+echo "Running dartanalyzer to check for errors/warnings..."
+dartanalyzer --strong --package-warnings \
     bin/dartdevc.dart web/main.dart \
-    | grep -v "\[info\] TODO" | (! grep $PWD) || fail
+    | grep -v "\[info\]" | grep -v "\[hint\]" | (! grep $PWD) || fail
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/collection/list.dart b/pkg/dev_compiler/tool/input_sdk/lib/collection/list.dart
index 7e6dbd3a..37fdf0a 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/collection/list.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/collection/list.dart
@@ -309,7 +309,7 @@
 
   void sort([int compare(E a, E b)]) {
     if (compare == null) {
-      Sort.sort(this, Comparable.compare);
+      Sort.sort(this, (a, b) => Comparable.compare(a, b));
     } else {
       Sort.sort(this, compare);
     }
diff --git a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
index 4a9ff79..c8a2c7e 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
@@ -554,7 +554,7 @@
 }
 
 class _Es6LinkedIdentityHashMap<K, V>
-    extends _LinkedIdentityHashMap<K, V> implements InternalMap {
+    extends _LinkedIdentityHashMap<K, V> implements InternalMap<K, V> {
   final _map;
   int _modifications = 0;
 
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index 72538db..d30b628 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -33,7 +33,7 @@
 
 dload(obj, field) {
   var f = _canonicalMember(obj, field);
-  _trackCall(obj, f);
+  _trackCall(obj);
   if (f != null) {
     if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0'));
     return JS('', '#[#]', obj, f);
@@ -44,7 +44,7 @@
 
 dput(obj, field, value) {
   var f = _canonicalMember(obj, field);
-  _trackCall(obj, f);
+  _trackCall(obj);
   if (f != null) {
     return JS('', '#[#] = #', obj, f, value);
   }
@@ -106,7 +106,7 @@
 }
 
 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => {
-  $_trackCall($obj, $name);
+  $_trackCall($obj);
 
   let originalTarget = obj === void 0 ? f : obj;
 
@@ -182,17 +182,28 @@
 dgcall(f, typeArgs, @rest args) => _checkAndCall(
     f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call');
 
-Map<String, int> _callMethodStats = new Map();
+class _MethodStats {
+  final String typeName;
+  final String frame;
+  int count;
+
+  _MethodStats(this.typeName, this.frame) {
+    count = 0;
+  }
+}
+
+Map<String, _MethodStats> _callMethodStats = new Map();
 
 List<List<Object>> getDynamicStats() {
   List<List<Object>> ret = [];
 
   var keys = _callMethodStats.keys.toList();
 
-  keys.sort((a, b) => _callMethodStats[b].compareTo(_callMethodStats[a]));
+  keys.sort((a, b) => _callMethodStats[b].count.compareTo(
+      _callMethodStats[a].count));
   for (var key in keys) {
-    int count = _callMethodStats[key];
-    ret.add([key, count]);
+    var stats = _callMethodStats[key];
+    ret.add([stats.typeName, stats.frame, stats.count]);
   }
 
   return ret;
@@ -204,7 +215,7 @@
 
 bool trackProfile = JS('bool', 'dart.global.trackDdcProfile');
 
-_trackCall(obj, name) {
+_trackCall(obj) {
   if (JS('bool', '!#', trackProfile)) return;
 
   var actual = getReifiedType(obj);
@@ -219,12 +230,9 @@
     }
   }
 
-  name = "${typeName(actual)}.$name <$src>";
-  if (_callMethodStats.containsKey(name)) {
-    _callMethodStats[name] = _callMethodStats[name] + 1;
-  } else {
-    _callMethodStats[name] = 1;
-  }
+  var actualTypeName = typeName(actual);
+  _callMethodStats.putIfAbsent("$actualTypeName <$src>",
+      () => new _MethodStats(actualTypeName, src)).count++;
 }
 
 /// Shared code for dsend, dindex, and dsetindex.
diff --git a/pkg/dev_compiler/tool/input_sdk/private/isolate_serialization.dart b/pkg/dev_compiler/tool/input_sdk/private/isolate_serialization.dart
index 741cc2a..28c03f8 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/isolate_serialization.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/isolate_serialization.dart
@@ -114,7 +114,7 @@
     return x;
   }
 
-  serializeMap(Map x) {
+  serializeMap(InternalMap x) {
     Function serializeTearOff = serialize;
     return ['map',
             x.keys.map(serializeTearOff).toList(),
@@ -276,7 +276,7 @@
   }
 
   // ['map', <key-list>, <value-list>].
-  Map deserializeMap(x) {
+  Map deserializeMap(InternalMap x) {
     assert(x[0] == 'map');
     List keys = x[1];
     List values = x[2];
diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_array.dart b/pkg/dev_compiler/tool/input_sdk/private/js_array.dart
index bfb0a59..b937132 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/js_array.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/js_array.dart
@@ -463,7 +463,11 @@
 
   void sort([int compare(E a, E b)]) {
     checkMutable('sort');
-    Sort.sort(this, compare == null ? Comparable.compare : compare);
+    if (compare == null) {
+      Sort.sort(this, (a, b) => Comparable.compare(a, b));
+    } else {
+      Sort.sort(this, compare);
+    }
   }
 
   void shuffle([Random random]) {
diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_helper.dart b/pkg/dev_compiler/tool/input_sdk/private/js_helper.dart
index d3c372b..09e9a78 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/js_helper.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/js_helper.dart
@@ -33,8 +33,7 @@
 
 /// Marks the internal map in dart2js, so that internal libraries can is-check
 // them.
-abstract class InternalMap {
-}
+abstract class InternalMap<K, V> implements Map<K, V> {}
 
 class Primitives {
   /// Isolate-unique ID for caching [JsClosureMirror.function].
diff --git a/pkg/dev_compiler/tool/input_sdk/private/linked_hash_map.dart b/pkg/dev_compiler/tool/input_sdk/private/linked_hash_map.dart
index 7ea72b7..f6c20bf 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/linked_hash_map.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/linked_hash_map.dart
@@ -10,7 +10,7 @@
 // DDC-specific, just use Object-backed maps
 //const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
 
-class JsLinkedHashMap<K, V> implements LinkedHashMap<K, V>, InternalMap {
+class JsLinkedHashMap<K, V> implements LinkedHashMap<K, V>, InternalMap<K, V> {
   int _length = 0;
 
   // The hash map contents are divided into three parts: one part for
diff --git a/pkg/dev_compiler/tool/run.js b/pkg/dev_compiler/tool/run.js
new file mode 100644
index 0000000..4d186072
--- /dev/null
+++ b/pkg/dev_compiler/tool/run.js
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, 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.
+
+var args = process.argv.slice(2);
+if (args.length != 1) {
+  throw new Error("Usage: node test/run.js <test-module-name>");
+}
+var test = args[0];
+
+var requirejs = require('requirejs');
+var ddcdir = __dirname + '/..';
+requirejs.config({
+  baseUrl: ddcdir + '/gen/codegen_output',
+  paths: {
+    dart_sdk: ddcdir + '/lib/js/amd/dart_sdk'
+  }
+});
+
+// TODO(vsm): Factor out test framework code in test/browser/language_tests.js
+// and use here.  Async tests and unittests won't work without it.
+
+var module = requirejs(test);
+test = test.split('/').slice(-1)[0];
+module[test].main();
diff --git a/pkg/dev_compiler/tool/sdk_expected_errors.txt b/pkg/dev_compiler/tool/sdk_expected_errors.txt
index ac10927..a7b684d 100644
--- a/pkg/dev_compiler/tool/sdk_expected_errors.txt
+++ b/pkg/dev_compiler/tool/sdk_expected_errors.txt
@@ -1,11 +1,7 @@
-[error] The argument type 'InternalMap' cannot be assigned to the parameter type 'Map'. (dart:_isolate_helper/isolate_serialization.dart, line 47, col 47)
-[error] Could not infer type parameter E, E must be of type <bottom>. (dart:_interceptors/js_array.dart, line 466, col 10)
-[error] Base class introduces an invalid override. The type of JSArray.[]= ((int, E) → void) is not a subtype of JSMutableIndexable.[]= ((int, dynamic) → dynamic). (dart:_interceptors/js_array.dart, line 586, col 25)
+[error] Base class introduces an invalid override. The type of JSArray.[]= ((int, E) → void) is not a subtype of JSMutableIndexable.[]= ((int, dynamic) → dynamic). (dart:_interceptors/js_array.dart, line 590, col 25)
 [error] Invalid override. The type of NativeTypedArrayOfDouble.[]= ((int, num) → void) is not a subtype of JSMutableIndexable.[]= ((int, dynamic) → dynamic). (dart:_native_typed_data, line 793, col 3)
 [error] Could not infer type parameter T, _ControllerEventSinkWrapper<dynamic> must be of type EventSink<T>. (dart:async/stream.dart, line 1346, col 16)
 [error] The argument type '_ControllerEventSinkWrapper' cannot be assigned to the parameter type 'EventSink<T>'. (dart:async/stream.dart, line 1346, col 53)
-[error] Could not infer type parameter E, E must be of type Comparable<dynamic>. (dart:collection/list.dart, line 312, col 12)
-[error] The argument type 'ListMixin<E>' cannot be assigned to the parameter type 'List<Comparable>'. (dart:collection/list.dart, line 312, col 17)
 [error] Invalid override. The type of ChunkedConverter.bind ((dynamic) → dynamic) is not a subtype of Converter<S, T>.bind ((Stream<S>) → Stream<T>). (dart:convert/chunked_conversion.dart, line 14, col 3)
 [error] Invalid override. The type of ChunkedConverter.bind ((dynamic) → dynamic) is not a subtype of StreamTransformer<S, T>.bind ((Stream<S>) → Stream<T>). (dart:convert/chunked_conversion.dart, line 14, col 3)
 [error] Invalid override. The type of ChunkedConverter.startChunkedConversion ((dynamic) → dynamic) is not a subtype of Converter<S, T>.startChunkedConversion ((Sink<T>) → Sink<S>). (dart:convert/chunked_conversion.dart, line 15, col 3)
@@ -45,10 +41,9 @@
 [warning] Unsound implicit cast from dynamic to E (dart:_interceptors/js_array.dart, line 300, col 17)
 [warning] Unsound implicit cast from dynamic to E (dart:_interceptors/js_array.dart, line 443, col 27)
 [warning] Unsound implicit cast from dynamic to E (dart:_interceptors/js_array.dart, line 455, col 27)
-[warning] Unsound implicit cast from (<bottom>, <bottom>) → int to (E, E) → int (dart:_interceptors/js_array.dart, line 466, col 21)
-[warning] Unsound implicit cast from dynamic to E (dart:_interceptors/js_array.dart, line 560, col 12)
-[warning] Unsound implicit cast from dynamic to JSArray<String> (dart:_js_helper, line 80, col 37)
-[warning] Unsound implicit cast from dynamic to E (dart:_js_helper, line 883, col 16)
+[warning] Unsound implicit cast from dynamic to E (dart:_interceptors/js_array.dart, line 564, col 12)
+[warning] Unsound implicit cast from dynamic to JSArray<String> (dart:_js_helper, line 79, col 37)
+[warning] Unsound implicit cast from dynamic to E (dart:_js_helper, line 882, col 16)
 [warning] Unsound implicit cast from dynamic to () → List<Type> (dart:_js_mirrors, line 356, col 40)
 [warning] Unsound implicit cast from dynamic to List<String> (dart:_interceptors/js_string.dart, line 92, col 14)
 [warning] Unsound implicit cast from dynamic to List<String> (dart:_interceptors/js_string.dart, line 95, col 14)
diff --git a/pkg/dev_compiler/web/main.dart b/pkg/dev_compiler/web/main.dart
index ebf3a91..a604412 100755
--- a/pkg/dev_compiler/web/main.dart
+++ b/pkg/dev_compiler/web/main.dart
@@ -3,38 +3,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.
 
-/// Command line entry point for Dart Development Compiler (dartdevc).
-///
-/// Supported commands are
-///   * compile: builds a collection of dart libraries into a single JS module
-///
-/// Additionally, these commands are being considered
-///   * link:  combines several JS modules into a single JS file
-///   * build: compiles & links a set of code, automatically determining
-///            appropriate groupings of libraries to combine into JS modules
-///   * watch: watch a directory and recompile build units automatically
-///   * serve: uses `watch` to recompile and exposes a simple static file server
-///            for local development
-///
-/// These commands are combined so we have less names to expose on the PATH,
-/// and for development simplicity while the precise UI has not been determined.
-///
-/// A more typical structure for web tools is simply to have the compiler with
-/// "watch" as an option. The challenge for us is:
-///
-/// * Dart used to assume whole-program compiles, so we don't have a
-///   user-declared unit of building, and neither "libraries" or "packages" will
-///   work,
-/// * We do not assume a `node` JS installation, so we cannot easily reuse
-///   existing tools for the "link" step, or assume users have a local
-///   file server,
-/// * We didn't have a file watcher API at first,
-/// * We had no conventions about where compiled output should go (or even
-///   that we would be compiling at all, vs running on an in-browser Dart VM),
-/// * We wanted a good first impression with our simple examples, so we used
-///   local file servers, and users have an expectation of it now, even though
-///   it doesn't scale to typical apps that need their own real servers.
-
 @JS()
 library dev_compiler.web.main;
 
@@ -45,7 +13,7 @@
 
 import 'web_command.dart';
 
-@JS()
+@JS(r'$setUpDartDevCompilerInBrowser')
 external set setUpCompilerInBrowser(Function function);
 
 Future main() async {
@@ -61,7 +29,7 @@
     // with ArgResults or ArgParsers.
     var runner = new CommandRunner('dartdevc', 'Dart Development Compiler');
     runner.addCommand(new WebCompileCommand(messageHandler: messageHandler));
-    setUpCompilerInBrowser = allowInterop(await runner.run(args));
+    setUpCompilerInBrowser = allowInterop((await runner.run(args)) as Function);
   } catch (e, s) {
     return _handleError(e, s, args, messageHandler: messageHandler);
   }
diff --git a/pkg/dev_compiler/web/web_command.dart b/pkg/dev_compiler/web/web_command.dart
index 171beb2..dc10142 100644
--- a/pkg/dev_compiler/web/web_command.dart
+++ b/pkg/dev_compiler/web/web_command.dart
@@ -33,6 +33,16 @@
 
 typedef void MessageHandler(Object message);
 
+@JS()
+@anonymous
+class CompileResult {
+  external factory CompileResult(
+      {String code, List<String> errors, bool isValid});
+}
+
+typedef CompileResult CompileModule(
+    String code, String libraryName, String fileName);
+
 /// The command for invoking the modular compiler.
 class WebCompileCommand extends Command {
   get name => 'compile';
@@ -75,7 +85,7 @@
         (error) => onError('Dart sdk summaries failed to load: $error'));
   }
 
-  Function setUpCompile(List<int> sdkBytes, List<List<int>> summaryBytes,
+  CompileModule setUpCompile(List<int> sdkBytes, List<List<int>> summaryBytes,
       List<String> summaryUrls) {
     var resourceProvider = new MemoryResourceProvider();
     var resourceUriResolver = new ResourceUriResolver(resourceProvider);
@@ -107,21 +117,24 @@
 
     var compilerOptions = new CompilerOptions.fromArguments(argResults);
 
-    var compileFn = (String dart, int number) {
+    CompileModule compileFn =
+        (String sourceCode, String libraryName, String fileName) {
       // Create a new virtual File that contains the given Dart source.
-      resourceProvider.newFile("/expression${number}.dart", dart);
+      resourceProvider.newFile("/$fileName", sourceCode);
 
-      var unit = new BuildUnit("expression${number}", "",
-          ["file:///expression${number}.dart"], _moduleForLibrary);
+      var unit = new BuildUnit(
+          libraryName, "", ["file:///$fileName"], _moduleForLibrary);
 
       JSModuleFile module = compiler.compile(unit, compilerOptions);
-      module.errors.forEach(messageHandler);
 
-      if (!module.isValid) throw new CompileErrorException();
+      var moduleCode = module.isValid
+          ? module
+              .getCode(ModuleFormat.legacy, unit.name, unit.name + '.map')
+              .code
+          : '';
 
-      var code =
-          module.getCode(ModuleFormat.amd, unit.name, unit.name + '.map');
-      return code.code;
+      return new CompileResult(
+          code: moduleCode, isValid: module.isValid, errors: module.errors);
     };
 
     return allowInterop(compileFn);
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 5b62b20..0be9565 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -7,7 +7,7 @@
 #include "bin/dartutils.h"
 #include "bin/file.h"
 #include "bin/platform.h"
-
+#include "platform/assert.h"
 #include "vm/benchmark_test.h"
 #include "vm/dart.h"
 #include "vm/unit_test.h"
@@ -88,6 +88,7 @@
       // List all tests and benchmarks and exit without initializing the VM.
       TestCaseBase::RunAll();
       Benchmark::RunAll(argv[0]);
+      fflush(stdout);
       return 0;
     } else if (strcmp(argv[1], "--benchmarks") == 0) {
       run_filter = kAllBenchmarks;
@@ -121,21 +122,17 @@
   // Apply the filter to all registered benchmarks.
   Benchmark::RunAll(argv[0]);
 
-  if (Flags::IsSet("shutdown")) {
-    err_msg = Dart::Cleanup();
-    ASSERT(err_msg == NULL);
-  }
-
-#if defined(TARGET_OS_WINDOWS)
-  // TODO(zra): Remove once VM shuts down cleanly.
-  private_flag_windows_run_tls_destructors = false;
-#endif
+  err_msg = Dart::Cleanup();
+  ASSERT(err_msg == NULL);
 
   // Print a warning message if no tests or benchmarks were matched.
   if (run_matches == 0) {
     fprintf(stderr, "No tests matched: %s\n", run_filter);
     return 1;
   }
+  if (DynamicAssertionHelper::failed()) {
+    return 255;
+  }
   return 0;
 }
 
@@ -143,5 +140,5 @@
 
 
 int main(int argc, const char** argv) {
-  return dart::Main(argc, argv);
+  dart::bin::Platform::Exit(dart::Main(argc, argv));
 }
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index 328323e..4525a7f 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -272,14 +272,14 @@
       p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state);
   RETURN_IF_ERROR(r);
 
-  mx_process_info_t proc_info;
+  mx_info_process_t proc_info;
   mx_ssize_t info_size = mx_object_get_info(
-      p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info));
+      p, MX_INFO_PROCESS, sizeof(proc_info.rec), &proc_info, sizeof(proc_info));
   RETURN_IF_ERROR(info_size);
 
   r = mx_handle_close(p);
   RETURN_IF_ERROR(r);
-  return proc_info.return_code;
+  return proc_info.rec.return_code;
 }
 
 
diff --git a/runtime/lib/internal_patch.dart b/runtime/lib/internal_patch.dart
index d19430f..88bff92 100644
--- a/runtime/lib/internal_patch.dart
+++ b/runtime/lib/internal_patch.dart
@@ -35,3 +35,11 @@
 final bool is64Bit = _inquireIs64Bit();
 
 bool _inquireIs64Bit() native "Internal_inquireIs64Bit";
+
+bool _classRangeCheck(int cid, int lowerLimit, int upperLimit) {
+  return cid >= lowerLimit && cid <= upperLimit;
+}
+
+bool _classRangeCheckNegative(int cid, int lowerLimit, int upperLimit) {
+  return cid < lowerLimit || cid > upperLimit;
+}
diff --git a/runtime/observatory/lib/app.dart b/runtime/observatory/lib/app.dart
index 3a47f1b..e8c0f4a 100644
--- a/runtime/observatory/lib/app.dart
+++ b/runtime/observatory/lib/app.dart
@@ -16,7 +16,6 @@
 import 'package:observatory/repositories.dart';
 import 'package:observatory/tracer.dart';
 import 'package:observatory/utils.dart';
-import 'package:polymer/polymer.dart';
 import 'package:usage/usage_html.dart';
 
 export 'package:observatory/utils.dart';
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index 5531b66..ece7d3f 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -1,31 +1,16 @@
 library observatory_elements;
 
-// Export elements.
-export 'package:observatory/src/elements/action_link.dart';
-export 'package:observatory/src/elements/class_ref_as_value.dart';
-export 'package:observatory/src/elements/debugger.dart';
-export 'package:observatory/src/elements/eval_link.dart';
-export 'package:observatory/src/elements/isolate_reconnect.dart';
-export 'package:observatory/src/elements/library_ref_as_value.dart';
-export 'package:observatory/src/elements/metrics.dart';
-export 'package:observatory/src/elements/observatory_element.dart';
-export 'package:observatory/src/elements/service_ref.dart';
-export 'package:observatory/src/elements/vm_connect.dart';
-
 import 'dart:async';
 
 import 'package:observatory/src/elements/allocation_profile.dart';
 import 'package:observatory/src/elements/class_allocation_profile.dart';
 import 'package:observatory/src/elements/class_instances.dart';
 import 'package:observatory/src/elements/class_ref.dart';
-import 'package:observatory/src/elements/class_ref_wrapper.dart';
 import 'package:observatory/src/elements/class_tree.dart';
 import 'package:observatory/src/elements/class_view.dart';
 import 'package:observatory/src/elements/code_ref.dart';
-import 'package:observatory/src/elements/code_ref_wrapper.dart';
 import 'package:observatory/src/elements/code_view.dart';
 import 'package:observatory/src/elements/context_ref.dart';
-import 'package:observatory/src/elements/context_ref_wrapper.dart';
 import 'package:observatory/src/elements/context_view.dart';
 import 'package:observatory/src/elements/containers/virtual_collection.dart';
 import 'package:observatory/src/elements/containers/virtual_tree.dart';
@@ -33,18 +18,14 @@
 import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
 import 'package:observatory/src/elements/cpu_profile_table.dart';
 import 'package:observatory/src/elements/curly_block.dart';
-import 'package:observatory/src/elements/curly_block_wrapper.dart';
+import 'package:observatory/src/elements/debugger.dart';
 import 'package:observatory/src/elements/error_ref.dart';
-import 'package:observatory/src/elements/error_ref_wrapper.dart';
 import 'package:observatory/src/elements/error_view.dart';
 import 'package:observatory/src/elements/eval_box.dart';
-import 'package:observatory/src/elements/eval_box_wrapper.dart';
 import 'package:observatory/src/elements/field_ref.dart';
-import 'package:observatory/src/elements/field_ref_wrapper.dart';
 import 'package:observatory/src/elements/field_view.dart';
 import 'package:observatory/src/elements/flag_list.dart';
 import 'package:observatory/src/elements/function_ref.dart';
-import 'package:observatory/src/elements/function_ref_wrapper.dart';
 import 'package:observatory/src/elements/function_view.dart';
 import 'package:observatory/src/elements/general_error.dart';
 import 'package:observatory/src/elements/heap_map.dart';
@@ -52,11 +33,9 @@
 import 'package:observatory/src/elements/icdata_ref.dart';
 import 'package:observatory/src/elements/icdata_view.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
-import 'package:observatory/src/elements/instance_ref_wrapper.dart';
 import 'package:observatory/src/elements/instance_view.dart';
 import 'package:observatory/src/elements/isolate_reconnect.dart';
 import 'package:observatory/src/elements/isolate_ref.dart';
-import 'package:observatory/src/elements/isolate_ref_wrapper.dart';
 import 'package:observatory/src/elements/isolate_view.dart';
 import 'package:observatory/src/elements/isolate/counter_chart.dart';
 import 'package:observatory/src/elements/isolate/location.dart';
@@ -65,37 +44,27 @@
 import 'package:observatory/src/elements/isolate/summary.dart';
 import 'package:observatory/src/elements/json_view.dart';
 import 'package:observatory/src/elements/library_ref.dart';
-import 'package:observatory/src/elements/library_ref_wrapper.dart';
 import 'package:observatory/src/elements/library_view.dart';
 import 'package:observatory/src/elements/local_var_descriptors_ref.dart';
 import 'package:observatory/src/elements/logging.dart';
 import 'package:observatory/src/elements/megamorphiccache_ref.dart';
 import 'package:observatory/src/elements/megamorphiccache_view.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/metrics.dart';
+import 'package:observatory/src/elements/metric/details.dart';
+import 'package:observatory/src/elements/metric/graph.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
-import 'package:observatory/src/elements/nav/class_menu_wrapper.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/isolate_menu_wrapper.dart';
 import 'package:observatory/src/elements/nav/library_menu.dart';
-import 'package:observatory/src/elements/nav/library_menu_wrapper.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
-import 'package:observatory/src/elements/nav/menu_wrapper.dart';
 import 'package:observatory/src/elements/nav/menu_item.dart';
-import 'package:observatory/src/elements/nav/menu_item_wrapper.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
-import 'package:observatory/src/elements/nav/notify_wrapper.dart';
 import 'package:observatory/src/elements/nav/notify_event.dart';
 import 'package:observatory/src/elements/nav/notify_exception.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
-import 'package:observatory/src/elements/nav/refresh_wrapper.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
-import 'package:observatory/src/elements/nav/top_menu_wrapper.dart';
 import 'package:observatory/src/elements/nav/vm_menu.dart';
-import 'package:observatory/src/elements/nav/vm_menu_wrapper.dart';
 import 'package:observatory/src/elements/objectpool_ref.dart';
 import 'package:observatory/src/elements/objectpool_view.dart';
 import 'package:observatory/src/elements/object_common.dart';
-import 'package:observatory/src/elements/object_common_wrapper.dart';
 import 'package:observatory/src/elements/object_view.dart';
 import 'package:observatory/src/elements/objectstore_view.dart';
 import 'package:observatory/src/elements/observatory_application.dart';
@@ -104,16 +73,12 @@
 import 'package:observatory/src/elements/ports.dart';
 import 'package:observatory/src/elements/sample_buffer_control.dart';
 import 'package:observatory/src/elements/script_inset.dart';
-import 'package:observatory/src/elements/script_inset_wrapper.dart';
 import 'package:observatory/src/elements/script_ref.dart';
-import 'package:observatory/src/elements/script_ref_wrapper.dart';
 import 'package:observatory/src/elements/script_view.dart';
 import 'package:observatory/src/elements/sentinel_value.dart';
 import 'package:observatory/src/elements/sentinel_view.dart';
 import 'package:observatory/src/elements/source_inset.dart';
-import 'package:observatory/src/elements/source_inset_wrapper.dart';
 import 'package:observatory/src/elements/source_link.dart';
-import 'package:observatory/src/elements/source_link_wrapper.dart';
 import 'package:observatory/src/elements/stack_trace_tree_config.dart';
 import 'package:observatory/src/elements/strongly_reachable_instances.dart';
 import 'package:observatory/src/elements/timeline_page.dart';
@@ -143,6 +108,7 @@
 export 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
 export 'package:observatory/src/elements/cpu_profile_table.dart';
 export 'package:observatory/src/elements/curly_block.dart';
+export 'package:observatory/src/elements/debugger.dart';
 export 'package:observatory/src/elements/error_ref.dart';
 export 'package:observatory/src/elements/error_view.dart';
 export 'package:observatory/src/elements/eval_box.dart';
@@ -173,11 +139,12 @@
 export 'package:observatory/src/elements/logging.dart';
 export 'package:observatory/src/elements/megamorphiccache_ref.dart';
 export 'package:observatory/src/elements/megamorphiccache_view.dart';
-export 'package:observatory/src/elements/nav/bar.dart';
+export 'package:observatory/src/elements/metrics.dart';
+export 'package:observatory/src/elements/metric/details.dart';
+export 'package:observatory/src/elements/metric/graph.dart';
 export 'package:observatory/src/elements/nav/class_menu.dart';
 export 'package:observatory/src/elements/nav/isolate_menu.dart';
 export 'package:observatory/src/elements/nav/library_menu.dart';
-export 'package:observatory/src/elements/nav/menu.dart';
 export 'package:observatory/src/elements/nav/menu_item.dart';
 export 'package:observatory/src/elements/nav/notify.dart';
 export 'package:observatory/src/elements/nav/notify_event.dart';
@@ -220,31 +187,29 @@
   ClassAllocationProfileElement.tag.ensureRegistration();
   ClassInstancesElement.tag.ensureRegistration();
   ClassRefElement.tag.ensureRegistration();
-  ClassRefElementWrapper.tag.ensureRegistration();
   ClassTreeElement.tag.ensureRegistration();
   ClassViewElement.tag.ensureRegistration();
   CodeRefElement.tag.ensureRegistration();
-  CodeRefElementWrapper.tag.ensureRegistration();
   CodeViewElement.tag.ensureRegistration();
   ContextRefElement.tag.ensureRegistration();
-  ContextRefElementWrapper.tag.ensureRegistration();
   ContextViewElement.tag.ensureRegistration();
   CpuProfileElement.tag.ensureRegistration();
   CpuProfileTableElement.tag.ensureRegistration();
   CpuProfileVirtualTreeElement.tag.ensureRegistration();
   CurlyBlockElement.tag.ensureRegistration();
-  CurlyBlockElementWrapper.tag.ensureRegistration();
+  DebuggerPageElement.tag.ensureRegistration();
+  DebuggerInputElement.tag.ensureRegistration();
+  DebuggerStackElement.tag.ensureRegistration();
+  DebuggerFrameElement.tag.ensureRegistration();
+  DebuggerMessageElement.tag.ensureRegistration();
+  DebuggerConsoleElement.tag.ensureRegistration();
   ErrorRefElement.tag.ensureRegistration();
-  ErrorRefElementWrapper.tag.ensureRegistration();
   ErrorViewElement.tag.ensureRegistration();
   EvalBoxElement.tag.ensureRegistration();
-  EvalBoxElementWrapper.tag.ensureRegistration();
   FieldRefElement.tag.ensureRegistration();
-  FieldRefElementWrapper.tag.ensureRegistration();
   FieldViewElement.tag.ensureRegistration();
   FlagListElement.tag.ensureRegistration();
   FunctionRefElement.tag.ensureRegistration();
-  FunctionRefElementWrapper.tag.ensureRegistration();
   FunctionViewElement.tag.ensureRegistration();
   GeneralErrorElement.tag.ensureRegistration();
   HeapMapElement.tag.ensureRegistration();
@@ -252,48 +217,36 @@
   ICDataRefElement.tag.ensureRegistration();
   ICDataViewElement.tag.ensureRegistration();
   InstanceRefElement.tag.ensureRegistration();
-  InstanceRefElementWrapper.tag.ensureRegistration();
   InstanceViewElement.tag.ensureRegistration();
   IsolateCounterChartElement.tag.ensureRegistration();
   IsolateLocationElement.tag.ensureRegistration();
   IsolateReconnectElement.tag.ensureRegistration();
   IsolateRefElement.tag.ensureRegistration();
-  IsolateRefElementWrapper.tag.ensureRegistration();
   IsolateRunStateElement.tag.ensureRegistration();
   IsolateSharedSummaryElement.tag.ensureRegistration();
   IsolateSummaryElement.tag.ensureRegistration();
   IsolateViewElement.tag.ensureRegistration();
   JSONViewElement.tag.ensureRegistration();
   LibraryRefElement.tag.ensureRegistration();
-  LibraryRefElementWrapper.tag.ensureRegistration();
   LibraryViewElement.tag.ensureRegistration();
   LocalVarDescriptorsRefElement.tag.ensureRegistration();
   LoggingPageElement.tag.ensureRegistration();
   MegamorphicCacheRefElement.tag.ensureRegistration();
   MegamorphicCacheViewElement.tag.ensureRegistration();
-  NavBarElement.tag.ensureRegistration();
+  MetricDetailsElement.tag.ensureRegistration();
+  MetricGraphElement.tag.ensureRegistration();
+  MetricsPageElement.tag.ensureRegistration();
   NavClassMenuElement.tag.ensureRegistration();
-  NavClassMenuElementWrapper.tag.ensureRegistration();
   NavIsolateMenuElement.tag.ensureRegistration();
-  NavIsolateMenuElementWrapper.tag.ensureRegistration();
   NavLibraryMenuElement.tag.ensureRegistration();
-  NavLibraryMenuElementWrapper.tag.ensureRegistration();
-  NavMenuElement.tag.ensureRegistration();
-  NavMenuElementWrapper.tag.ensureRegistration();
   NavMenuItemElement.tag.ensureRegistration();
-  NavMenuItemElementWrapper.tag.ensureRegistration();
   NavNotifyElement.tag.ensureRegistration();
-  NavNotifyElementWrapper.tag.ensureRegistration();
   NavNotifyEventElement.tag.ensureRegistration();
   NavNotifyExceptionElement.tag.ensureRegistration();
   NavRefreshElement.tag.ensureRegistration();
-  NavRefreshElementWrapper.tag.ensureRegistration();
   NavTopMenuElement.tag.ensureRegistration();
-  NavTopMenuElementWrapper.tag.ensureRegistration();
   NavVMMenuElement.tag.ensureRegistration();
-  NavVMMenuElementWrapper.tag.ensureRegistration();
   ObjectCommonElement.tag.ensureRegistration();
-  ObjectCommonElementWrapper.tag.ensureRegistration();
   ObjectViewElement.tag.ensureRegistration();
   ObjectPoolRefElement.tag.ensureRegistration();
   ObjectPoolViewElement.tag.ensureRegistration();
@@ -303,17 +256,13 @@
   PcDescriptorsRefElement.tag.ensureRegistration();
   PortsElement.tag.ensureRegistration();
   ScriptInsetElement.tag.ensureRegistration();
-  ScriptInsetElementWrapper.tag.ensureRegistration();
   SampleBufferControlElement.tag.ensureRegistration();
   ScriptRefElement.tag.ensureRegistration();
-  ScriptRefElementWrapper.tag.ensureRegistration();
   ScriptViewElement.tag.ensureRegistration();
   SentinelValueElement.tag.ensureRegistration();
   SentinelViewElement.tag.ensureRegistration();
   SourceInsetElement.tag.ensureRegistration();
-  SourceInsetElementWrapper.tag.ensureRegistration();
   SourceLinkElement.tag.ensureRegistration();
-  SourceLinkElementWrapper.tag.ensureRegistration();
   StackTraceTreeConfigElement.tag.ensureRegistration();
   StronglyReachableInstancesElement.tag.ensureRegistration();
   TimelinePageElement.tag.ensureRegistration();
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
deleted file mode 100644
index d62801f..0000000
--- a/runtime/observatory/lib/elements.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<link rel="import" href="src/elements/action_link.html">
-<link rel="import" href="src/elements/class_ref_as_value.html">
-<link rel="import" href="src/elements/debugger.html">
-<link rel="import" href="src/elements/eval_link.html">
-<link rel="import" href="src/elements/library_ref_as_value.html">
-<link rel="import" href="src/elements/metrics.html">
-<link rel="import" href="src/elements/service_ref.html">
diff --git a/runtime/observatory/lib/models.dart b/runtime/observatory/lib/models.dart
index 4e5dc53..a196975 100644
--- a/runtime/observatory/lib/models.dart
+++ b/runtime/observatory/lib/models.dart
@@ -31,6 +31,7 @@
 part 'src/models/objects/local_var_descriptors.dart';
 part 'src/models/objects/map_association.dart';
 part 'src/models/objects/megamorphiccache.dart';
+part 'src/models/objects/metric.dart';
 part 'src/models/objects/notification.dart';
 part 'src/models/objects/object.dart';
 part 'src/models/objects/objectpool.dart';
@@ -66,6 +67,7 @@
 part 'src/models/repositories/isolate.dart';
 part 'src/models/repositories/library.dart';
 part 'src/models/repositories/megamorphiccache.dart';
+part 'src/models/repositories/metric.dart';
 part 'src/models/repositories/notification.dart';
 part 'src/models/repositories/objectpool.dart';
 part 'src/models/repositories/object.dart';
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
index 96006fd..03e6cc6 100644
--- a/runtime/observatory/lib/repositories.dart
+++ b/runtime/observatory/lib/repositories.dart
@@ -31,6 +31,7 @@
 part 'src/repositories/isolate.dart';
 part 'src/repositories/library.dart';
 part 'src/repositories/megamorphiccache.dart';
+part 'src/repositories/metric.dart';
 part 'src/repositories/notification.dart';
 part 'src/repositories/objectpool.dart';
 part 'src/repositories/object.dart';
diff --git a/runtime/observatory/lib/service.dart b/runtime/observatory/lib/service.dart
index 37944d0..07f377c 100644
--- a/runtime/observatory/lib/service.dart
+++ b/runtime/observatory/lib/service.dart
@@ -14,6 +14,5 @@
 import 'package:observatory/event.dart' show createEventFromServiceEvent;
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/tracer.dart';
-import 'package:observe/observe.dart';
 
 part 'src/service/object.dart';
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index ff4fd3d..5306b13 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -6,7 +6,7 @@
 
 /// The observatory application. Instances of this are created and owned
 /// by the observatory_application custom element.
-class ObservatoryApplication extends Observable {
+class ObservatoryApplication {
   static ObservatoryApplication app;
   final RenderingQueue queue = new RenderingQueue();
   final TargetRepository targets = new TargetRepository();
@@ -15,7 +15,7 @@
   final _pageRegistry = new List<Page>();
   LocationManager _locationManager;
   LocationManager get locationManager => _locationManager;
-  @observable Page currentPage;
+  Page currentPage;
   VM _vm;
   VM get vm => _vm;
 
@@ -88,9 +88,9 @@
   }
 
 
-  @reflectable final ObservatoryApplicationElement rootElement;
+  final ObservatoryApplicationElement rootElement;
 
-  @reflectable ServiceObject lastErrorOrException;
+  ServiceObject lastErrorOrException;
 
   void _initOnce() {
     assert(app == null);
diff --git a/runtime/observatory/lib/src/app/location_manager.dart b/runtime/observatory/lib/src/app/location_manager.dart
index aadf653..ae684b8 100644
--- a/runtime/observatory/lib/src/app/location_manager.dart
+++ b/runtime/observatory/lib/src/app/location_manager.dart
@@ -4,7 +4,7 @@
 
 part of app;
 
-class LocationManager extends Observable {
+class LocationManager {
   final _defaultPath = '/vm';
 
   final ObservatoryApplication _app;
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 361ac7a..600199c 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -20,6 +20,7 @@
 final _isolateSampleProfileRepository = new IsolateSampleProfileRepository();
 final _libraryRepository = new LibraryRepository();
 final _megamorphicCacheRepository = new MegamorphicCacheRepository();
+final _metricRepository = new MetricRepository();
 final _objectRepository = new ObjectRepository();
 final _objectPoolRepository = new ObjectPoolRepository();
 final _objectstoreRepository = new ObjectStoreRepository();
@@ -47,11 +48,10 @@
 /// one page will be the current page. Pages are registered at startup.
 /// When the user navigates within the application, each page is asked if it
 /// can handle the current location, the first page to say yes, wins.
-abstract class Page extends Observable {
+abstract class Page {
   final ObservatoryApplication app;
-  final ObservableMap<String, String> internalArguments =
-      new ObservableMap<String, String>();
-  @observable HtmlElement element;
+  final Map<String, String> internalArguments = <String, String>{};
+  HtmlElement element;
 
   Page(this.app);
 
@@ -433,19 +433,33 @@
   }
 }
 
-class DebuggerPage extends SimplePage {
-  DebuggerPage(app) : super('debugger', 'debugger-page', app);
+class DebuggerPage extends MatchingPage {
+  DebuggerPage(app) : super('debugger', app);
+
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
-    getIsolate(uri).then((isolate) {
-      if (element != null) {
-        /// Update the page.
-        DebuggerPageElement page = element;
-        page.isolate = isolate;
-      }
+    getIsolate(uri).then((isolate) async {
+      container.children = [
+        new DebuggerPageElement(isolate, _instanceRepository,
+                                _scriptRepository, app.events)
+      ];
     });
   }
+
+  void onInstall() {
+    if (element == null) {
+      element = container;
+    }
+    assert(element != null);
+  }
+
+  @override
+  void onUninstall() {
+    super.onUninstall();
+    container.children = const [];
+  }
 }
 
 class ObjectStorePage extends MatchingPage {
@@ -546,9 +560,11 @@
     app.startGCEventListener();
   }
 
+  @override
   void onUninstall() {
     super.onUninstall();
     app.stopGCEventListener();
+    container.children = const [];
   }
 }
 
@@ -658,6 +674,8 @@
 
   @override
   void onUninstall() {
+    super.onUninstall();
+    container.children = const [];
     app.stopLoggingEventListener();
   }
 
@@ -736,63 +754,39 @@
   bool canVisit(Uri uri) => uri.path == 'isolate-reconnect';
 }
 
-class MetricsPage extends Page {
-  // Page state, retained as long as ObservatoryApplication.
-  String selectedMetricId;
+class MetricsPage extends MatchingPage {
+  MetricsPage(app) : super('metrics', app);
 
-  final Map<int, MetricPoller> pollers = new Map<int, MetricPoller>();
+  final DivElement container = new DivElement();
 
-  // 8 seconds, 4 seconds, 2 seconds, 1 second, and one hundred milliseconds.
-  static final List<int> POLL_PERIODS = [8000,
-                                         4000,
-                                         2000,
-                                         1000,
-                                         100];
+  Isolate lastIsolate;
 
-  MetricsPage(app) : super(app) {
-    for (var i = 0; i < POLL_PERIODS.length; i++) {
-      pollers[POLL_PERIODS[i]] = new MetricPoller(POLL_PERIODS[i]);
-    }
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) async {
+      lastIsolate = isolate;
+      container.children = const [];
+      await _metricRepository.startSampling(isolate);
+      container.children = [
+        new MetricsPageElement(isolate.vm, isolate, app.events,
+                               app.notifications, _metricRepository,
+                               queue: app.queue)
+      ];
+    });
   }
 
   void onInstall() {
     if (element == null) {
-      element = new Element.tag('metrics-page');
-      (element as MetricsPageElement).page = this;
+      element = container;
     }
-    assert(element != null);
   }
 
-  void setRefreshPeriod(int refreshPeriod, ServiceMetric metric) {
-    if (metric.poller != null) {
-      if (metric.poller.pollPeriod.inMilliseconds == refreshPeriod) {
-        return;
-      }
-      // Remove from current poller.
-      metric.poller.metrics.remove(metric);
-      metric.poller = null;
-    }
-    if (refreshPeriod == 0) {
-      return;
-    }
-    var poller = pollers[refreshPeriod];
-    if (poller != null) {
-      poller.metrics.add(metric);
-      metric.poller = poller;
-      return;
-    }
-    throw new FallThroughError();
+  @override
+  void onUninstall() {
+    super.onUninstall();
+    _metricRepository.stopSampling(lastIsolate);
+    container.children = const [];
   }
-
-  void _visit(Uri uri) {
-    assert(element != null);
-    assert(canVisit(uri));
-    app.vm.getIsolate(uri.queryParameters['isolateId']).then((i) {
-      (element as MetricsPageElement).isolate = i;
-    });
-  }
-
-  bool canVisit(Uri uri) => uri.path == 'metrics';
 }
 
 class TimelinePage extends Page {
diff --git a/runtime/observatory/lib/src/app/view_model.dart b/runtime/observatory/lib/src/app/view_model.dart
index 94edb49..e7e546f 100644
--- a/runtime/observatory/lib/src/app/view_model.dart
+++ b/runtime/observatory/lib/src/app/view_model.dart
@@ -4,272 +4,6 @@
 
 part of app;
 
-abstract class TableTreeRow extends Observable {
-  static const arrowRight = '\u2192';
-  static const arrowDownRight = '\u21b3';
-  // Number of ems each subtree is indented.
-  static const subtreeIndent = 2;
-
-  TableTreeRow(this.tree, TableTreeRow parent) :
-      parent = parent,
-      depth = parent != null ? parent.depth + 1 : 0 {
-  }
-
-  final TableTree tree;
-  final TableTreeRow parent;
-  final int depth;
-  final List<TableTreeRow> children = new List<TableTreeRow>();
-  final List<TableCellElement> _tableColumns = new List<TableCellElement>();
-  final List<DivElement> flexColumns = new List<DivElement>();
-  final List<StreamSubscription> listeners = new List<StreamSubscription>();
-
-  SpanElement _expander;
-  TableRowElement _tr;
-  TableRowElement get tr => _tr;
-  bool _expanded = false;
-  bool get expanded => _expanded;
-  set expanded(bool expanded) {
-    var changed = _expanded != expanded;
-    _expanded = expanded;
-    if (changed) {
-      // If the state has changed, fire callbacks.
-      if (_expanded) {
-        _onExpand();
-      } else {
-        _onCollapse();
-      }
-    }
-  }
-
-  /// Fired when the tree row is being expanded.
-  void _onExpand() {
-    _updateExpanderView();
-  }
-
-  /// Fired when the tree row is being collapsed.
-  void _onCollapse() {
-    for (var child in children) {
-      child.onHide();
-    }
-    _updateExpanderView();
-  }
-
-  bool toggle() {
-    expanded = !expanded;
-    return expanded;
-  }
-
-  HtmlElement _makeColorBlock(String backgroundColor) {
-    var colorBlock = new DivElement();
-    colorBlock.style.minWidth = '2px';
-    colorBlock.style.backgroundColor = backgroundColor;
-    return colorBlock;
-  }
-
-  HtmlElement _makeExpander() {
-    var expander = new SpanElement();
-    expander.style.minWidth = '24px';
-    expander.style.minHeight = '24px';
-    listeners.add(expander.onClick.listen(onClick));
-    return expander;
-  }
-
-  void _cleanUpListeners() {
-    for (var i = 0; i < listeners.length; i++) {
-      listeners[i].cancel();
-    }
-    listeners.clear();
-  }
-
-  void onClick(Event e) {
-    e.stopPropagation();
-    tree.toggle(this);
-  }
-
-  static const redColor = '#F44336';
-  static const blueColor = '#3F51B5';
-  static const purpleColor = '#673AB7';
-  static const greenColor = '#4CAF50';
-  static const orangeColor = '#FF9800';
-  static const lightGrayColor = '#FAFAFA';
-
-  void _buildRow() {
-    const List backgroundColors = const [
-      purpleColor,
-      redColor,
-      greenColor,
-      blueColor,
-      orangeColor,
-    ];
-    _tr = new TableRowElement();
-    for (var i = 0; i < tree.columnCount; i++) {
-      var cell = _tr.insertCell(-1);
-      _tableColumns.add(cell);
-      var flex = new DivElement();
-      flex.classes.add('flex-row');
-      cell.children.add(flex);
-      flexColumns.add(flex);
-    }
-    var firstColumn = flexColumns[0];
-    _tableColumns[0].style.paddingLeft = '${(depth - 1) * subtreeIndent}em';
-    var backgroundColor = lightGrayColor;
-    if (depth > 1) {
-      var colorIndex = (depth - 1) % backgroundColors.length;
-      backgroundColor = backgroundColors[colorIndex];
-    }
-    var colorBlock = _makeColorBlock(backgroundColor);
-    firstColumn.children.add(colorBlock);
-    _expander = _makeExpander();
-    firstColumn.children.add(_expander);
-    // Enable expansion by clicking anywhere on the first column.
-    listeners.add(firstColumn.onClick.listen(onClick));
-    _updateExpanderView();
-  }
-
-  void _updateExpanderView() {
-    if (_expander == null) {
-      return;
-    }
-    if (!hasChildren()) {
-      _expander.style.visibility = 'hidden';
-      _expander.classes.remove('pointer');
-      return;
-    } else {
-      _expander.style.visibility = 'visible';
-      _expander.classes.add('pointer');
-    }
-    _expander.children.clear();
-    _expander.children.add(expanded ?
-        new Element.tag('icon-expand-more') :
-        new Element.tag('icon-chevron-right'));
-  }
-
-  bool hasChildren();
-
-  /// Fired when the tree row is being shown.
-  /// Populate tr and add logical children here.
-  void onShow() {
-    assert(_tr == null);
-    _buildRow();
-  }
-
-  /// Fired when the tree row is being hidden.
-  void onHide() {
-    _tr = null;
-    _expander = null;
-    if (_tableColumns != null) {
-      _tableColumns.clear();
-    }
-    if (flexColumns != null) {
-      flexColumns.clear();
-    }
-    _cleanUpListeners();
-  }
-}
-
-class TableTree extends Observable {
-  final TableSectionElement tableBody;
-  final List<TableTreeRow> rows = [];
-  final int columnCount;
-  Future _pendingOperation;
-  /// Create a table tree with column [headers].
-  TableTree(this.tableBody, this.columnCount);
-
-  void clear() {
-    tableBody.children.clear();
-    for (var i = 0; i < rows.length; i++) {
-      rows[i]._cleanUpListeners();
-    }
-    rows.clear();
-  }
-
-  /// Initialize the table tree with the list of root children.
-  void initialize(TableTreeRow root) {
-    clear();
-    root.onShow();
-    toggle(root);
-  }
-
-  /// Toggle expansion of row in tree.
-  toggle(TableTreeRow row) async {
-    if (_pendingOperation != null) {
-      return;
-    }
-    if (row.toggle()) {
-      document.body.classes.add('busy');
-      _pendingOperation = _expand(row);
-      await _pendingOperation;
-      _pendingOperation = null;
-      document.body.classes.remove('busy');
-      if (row.children.length == 1) {
-        // Auto expand single child.
-        await toggle(row.children[0]);
-      }
-    } else {
-      document.body.classes.add('busy');
-      _pendingOperation = _collapse(row);
-      await _pendingOperation;
-      _pendingOperation = null;
-      document.body.classes.remove('busy');
-    }
-  }
-
-  int _index(TableTreeRow row) => rows.indexOf(row);
-
-  _insertRow(index, child) {
-    rows.insert(index, child);
-    tableBody.children.insert(index, child.tr);
-  }
-
-  _expand(TableTreeRow row) async {
-    int index = _index(row);
-    if ((index == -1) && (rows.length != 0)) {
-      return;
-    }
-    assert((index != -1) || (rows.length == 0));
-    var i = 0;
-    var addPerIteration = 10;
-    while (i < row.children.length) {
-      await window.animationFrame;
-      for (var j = 0; j < addPerIteration; j++) {
-        if (i == row.children.length) {
-          break;
-        }
-        var child = row.children[i];
-        child.onShow();
-        child._updateExpanderView();
-        _insertRow(index + i + 1, child);
-        i++;
-      }
-    }
-  }
-
-  _collapseSync(TableTreeRow row) {
-    var childCount = row.children.length;
-    if (childCount == 0) {
-      return;
-    }
-    for (var i = 0; i < childCount; i++) {
-      // Close all inner rows.
-      if (row.children[i].expanded) {
-        _collapseSync(row.children[i]);
-      }
-    }
-    // Collapse this row.
-    row.expanded = false;
-    // Remove all children.
-    int index = _index(row);
-    for (var i = 0; i < childCount; i++) {
-      rows.removeAt(index + 1);
-      tableBody.children.removeAt(index + 1);
-    }
-  }
-
-  _collapse(TableTreeRow row) async {
-    _collapseSync(row);
-  }
-}
-
 typedef String ValueFormatter(dynamic value);
 
 class SortedTableColumn {
@@ -288,7 +22,7 @@
   SortedTableRow(this.values);
 }
 
-class SortedTable extends Observable {
+class SortedTable {
   final List<SortedTableColumn> columns;
   final List<SortedTableRow> rows = new List<SortedTableRow>();
   final List<int> sortedRows = [];
@@ -300,14 +34,12 @@
     assert(index >= 0);
     assert(index < columns.length);
     _sortColumnIndex = index;
-    notifyPropertyChange(#getColumnLabel, 0, 1);
   }
   int get sortColumnIndex => _sortColumnIndex;
   bool _sortDescending = true;
   bool get sortDescending => _sortDescending;
   set sortDescending(var descending) {
     _sortDescending = descending;
-    notifyPropertyChange(#getColumnLabel, 0, 1);
   }
 
 
@@ -353,7 +85,7 @@
     return formatter(value);
   }
 
-  @observable String getColumnLabel(int column) {
+  String getColumnLabel(int column) {
     assert(column >= 0);
     assert(column < columns.length);
     // TODO(johnmccutchan): Move expander display decisions into html once
diff --git a/runtime/observatory/lib/src/cli/command.dart b/runtime/observatory/lib/src/cli/command.dart
index 04ff48e..b9eebb0 100644
--- a/runtime/observatory/lib/src/cli/command.dart
+++ b/runtime/observatory/lib/src/cli/command.dart
@@ -115,7 +115,13 @@
 
 // The root of a tree of commands.
 class RootCommand extends _CommandBase {
-  RootCommand(List<Command> children) : super(children);
+  RootCommand(List<Command> children, [List<String> history])
+     : this._(children, history ?? ['']);
+
+   RootCommand._(List<Command> children, List<String> history)
+      : history = history,
+        historyPos = history.length - 1,
+      super(children);
 
   // Provides a list of possible completions for a line of text.
   Future<List<String>> completeCommand(String line) {
@@ -191,8 +197,8 @@
 
   // Command line history always contains one slot to hold the current
   // line, so we start off with one entry.
-  List<String> history = [''];
-  int historyPos = 0;
+  List<String> history;
+  int historyPos;
 
   String historyPrev(String line) {
     if (historyPos == 0) {
diff --git a/runtime/observatory/lib/src/debugger/debugger.dart b/runtime/observatory/lib/src/debugger/debugger.dart
index b2d5203..ca7b0d9 100644
--- a/runtime/observatory/lib/src/debugger/debugger.dart
+++ b/runtime/observatory/lib/src/debugger/debugger.dart
@@ -8,6 +8,7 @@
 abstract class Debugger {
   VM get vm;
   Isolate get isolate;
+  M.InstanceRepository instances;
   ServiceMap get stack;
   int get currentFrame;
 }
diff --git a/runtime/observatory/lib/src/elements/action_link.dart b/runtime/observatory/lib/src/elements/action_link.dart
deleted file mode 100644
index 63b941e..0000000
--- a/runtime/observatory/lib/src/elements/action_link.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library action_link_element;
-
-import 'observatory_element.dart';
-import 'package:polymer/polymer.dart';
-
-@CustomTag('action-link')
-class ActionLinkElement extends ObservatoryElement {
-  ActionLinkElement.created() : super.created();
-
-  @observable bool busy = false;
-  @published var callback = null;
-  @published String label = 'action';
-  @published String color = null;
-
-  void doAction(var a, var b, var c) {
-    if (busy) {
-      return;
-    }
-    if (callback != null) {
-      busy = true;
-      callback()
-        .catchError(app.handleException)
-        .whenComplete(() {
-          busy = false;
-        });
-    }
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/action_link.html b/runtime/observatory/lib/src/elements/action_link.html
deleted file mode 100644
index 2bb0133..0000000
--- a/runtime/observatory/lib/src/elements/action_link.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="action-link">
-  <template>
-    <style>
-      .idle {
-        color: #0489c3;
-        cursor: pointer;
-        text-decoration: none;
-      }
-      .idle:hover {
-        text-decoration: underline;
-      }
-      .busy {
-        color: #aaa;
-        cursor: wait;
-        text-decoration: none;
-      }
-    </style>
-
-    <template if="{{ busy }}">
-      <span class="busy">[{{ label }}]</span>
-    </template>
-    <template if="{{ !busy }}">
-      <template if="{{ color == null }}">
-        <span class="idle"><a on-click="{{ doAction }}">[{{ label }}]</a></span>
-      </template>
-      <template if="{{ color != null }}">
-        <span class="idle" style="color:{{ color }}"><a on-click="{{ doAction }}">[{{ label }}]</a></span>
-      </template>
-    </template>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="action_link.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/allocation_profile.dart b/runtime/observatory/lib/src/elements/allocation_profile.dart
index 0fb63c0..f126544 100644
--- a/runtime/observatory/lib/src/elements/allocation_profile.dart
+++ b/runtime/observatory/lib/src/elements/allocation_profile.dart
@@ -9,12 +9,11 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/class_ref.dart';
 import 'package:observatory/src/elements/containers/virtual_collection.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -46,11 +45,9 @@
   static const tag = const Tag<AllocationProfileElement>('allocation-profile',
                                             dependencies: const [
                                               ClassRefElement.tag,
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               VirtualCollectionElement.tag
@@ -68,6 +65,7 @@
   M.AllocationProfileRepository _repository;
   M.AllocationProfile _profile;
   bool _autoRefresh = false;
+  bool _isCompacted = false;
   StreamSubscription _gcSubscription;
   _SortingField _sortingField =
       _SortingField.className;
@@ -122,34 +120,32 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('allocation profile', last: true,
-              link: Uris.allocationProfiler(_isolate), queue: _r.queue),
-          new NavRefreshElement(label: 'Download', disabled: _profile == null,
-              queue: _r.queue)
-            ..onRefresh.listen((_) => _downloadCSV()),
-          new NavRefreshElement(label: 'Reset Accumulator', queue: _r.queue)
-            ..onRefresh.listen((_) => _refresh(reset: true)),
-          new NavRefreshElement(label: 'GC', queue: _r.queue)
-            ..onRefresh.listen((_) => _refresh(gc: true)),
-          new NavRefreshElement(queue: _r.queue)
-            ..onRefresh.listen((_) => _refresh()),
-          new DivElement()..classes = ['nav-option']
-            ..children = [
-              new CheckboxInputElement()
-                ..id = 'allocation-profile-auto-refresh'
-                ..checked = _autoRefresh
-                ..onChange.listen((_) => _autoRefresh = !_autoRefresh),
-              new LabelElement()
-                ..htmlFor = 'allocation-profile-auto-refresh'
-                ..text = 'Auto-refresh on GC'
-            ],
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('allocation profile'),
+        new NavRefreshElement(label: 'Download', disabled: _profile == null,
+            queue: _r.queue)
+          ..onRefresh.listen((_) => _downloadCSV()),
+        new NavRefreshElement(label: 'Reset Accumulator', queue: _r.queue)
+          ..onRefresh.listen((_) => _refresh(reset: true)),
+        new NavRefreshElement(label: 'GC', queue: _r.queue)
+          ..onRefresh.listen((_) => _refresh(gc: true)),
+        new NavRefreshElement(queue: _r.queue)
+          ..onRefresh.listen((_) => _refresh()),
+        new DivElement()..classes = ['nav-option']
+          ..children = [
+            new CheckboxInputElement()
+              ..id = 'allocation-profile-auto-refresh'
+              ..checked = _autoRefresh
+              ..onChange.listen((_) => _autoRefresh = !_autoRefresh),
+            new LabelElement()
+              ..htmlFor = 'allocation-profile-auto-refresh'
+              ..text = 'Auto-refresh on GC'
+          ],
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Allocation Profile',
@@ -170,7 +166,7 @@
       final oldChartLegend = new DivElement()..classes = ['legend'];
       children.addAll([
         new DivElement()..classes = ['content-centered-big']
-          ..children = [
+          ..children = _isCompacted ? [] : [
             new DivElement()..classes = ['memberList']
               ..children = [
                 new DivElement()..classes = ['memberItem']
@@ -192,31 +188,50 @@
               ],
             new HRElement(),
           ],
-        new DivElement()..classes = ['content-centered-big']
+        new DivElement()..classes = ['content-centered-big', 'compactable']
           ..children = [
             new DivElement()..classes = ['heap-space', 'left']
-              ..children = [
-                new HeadingElement.h2()..text = 'New Generation',
-                new BRElement(),
-                new DivElement()..classes = ['memberList']
-                  ..children = _createSpaceMembers(_profile.newSpace),
-                new BRElement(),
-                new DivElement()..classes = ['chart']
-                  ..children = [newChartLegend, newChartHost]
-              ],
+              ..children = _isCompacted
+                ? [
+                  new HeadingElement.h2()
+                    ..text = 'New Generation '
+                             '(${_usedCaption(_profile.newSpace)})',
+                ]
+                : [
+                  new HeadingElement.h2()..text = 'New Generation',
+                  new BRElement(),
+                  new DivElement()..classes = ['memberList']
+                    ..children = _createSpaceMembers(_profile.newSpace),
+                  new BRElement(),
+                  new DivElement()..classes = ['chart']
+                    ..children = [newChartLegend, newChartHost]
+                ],
             new DivElement()..classes = ['heap-space', 'right']
-              ..children = [
-                new HeadingElement.h2()..text = 'Old Generation',
-                new BRElement(),
-                new DivElement()..classes = ['memberList']
-                  ..children = _createSpaceMembers(_profile.oldSpace),
-                new BRElement(),
-                new DivElement()..classes = ['chart']
-                  ..children = [oldChartLegend, oldChartHost]
-              ],
-            new BRElement(), new HRElement()
+              ..children = _isCompacted
+                ? [
+                  new HeadingElement.h2()
+                    ..text = '(${_usedCaption(_profile.newSpace)}) '
+                             'Old Generation',
+                ]
+                : [
+                  new HeadingElement.h2()..text = 'Old Generation',
+                  new BRElement(),
+                  new DivElement()..classes = ['memberList']
+                    ..children = _createSpaceMembers(_profile.oldSpace),
+                  new BRElement(),
+                  new DivElement()..classes = ['chart']
+                    ..children = [oldChartLegend, oldChartHost]
+                ],
+            new ButtonElement()..classes = ['compact']
+              ..text = _isCompacted ? 'expand â–¼' : 'compact â–²'
+              ..onClick.listen((_) {
+                _isCompacted = !_isCompacted;
+                _r.dirty();
+              }),
+            new HRElement()
           ],
-        new DivElement()..classes = ['collection']
+        new DivElement()
+          ..classes = _isCompacted ? ['collection', 'expanded'] : ['collection']
           ..children = [
             new VirtualCollectionElement(
               _createCollectionLine,
@@ -424,10 +439,13 @@
                       ..classes = ['name'];
   }
 
+  static String _usedCaption(M.HeapSpace space) =>
+    '${Utils.formatSize(space.used)}'
+    ' of '
+    '${Utils.formatSize(space.capacity)}';
+
   static List<Element> _createSpaceMembers(M.HeapSpace space) {
-    final used = '${Utils.formatSize(space.used)}'
-                 ' of '
-                 '${Utils.formatSize(space.capacity)}';
+    final used = _usedCaption(space);
     final ext = '${Utils.formatSize(space.external)}';
     final collections = '${space.collections}';
     final avgCollectionTime =
diff --git a/runtime/observatory/lib/src/elements/class_ref.dart b/runtime/observatory/lib/src/elements/class_ref.dart
index 8596d73..21bd6cc 100644
--- a/runtime/observatory/lib/src/elements/class_ref.dart
+++ b/runtime/observatory/lib/src/elements/class_ref.dart
@@ -10,7 +10,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class ClassRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<ClassRefElement>('class-ref-wrapped');
+  static const tag = const Tag<ClassRefElement>('class-ref');
 
   RenderingScheduler<ClassRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/class_ref_as_value.dart b/runtime/observatory/lib/src/elements/class_ref_as_value.dart
deleted file mode 100644
index 7e129f8..0000000
--- a/runtime/observatory/lib/src/elements/class_ref_as_value.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library class_ref_as_value_element;
-
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
-import 'dart:async';
-
-@CustomTag('class-ref-as-value')
-class ClassRefAsValueElement extends ServiceRefElement {
-
-  ClassRefAsValueElement.created() : super.created();
-
-  String makeExpandKey(String key) {
-    return '${expandKey}/${key}';
-  }
-
-  dynamic expander() {
-    return expandEvent;
-  }
-
-  void expandEvent(bool expand, Function onDone) {
-    if (expand) {
-      Class cls = ref;
-      cls.reload().then((result) {
-        return Future.wait(cls.fields.map((field) => field.reload()));
-      }).whenComplete(onDone);
-    } else {
-      onDone();
-    }
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/class_ref_as_value.html b/runtime/observatory/lib/src/elements/class_ref_as_value.html
deleted file mode 100644
index a148981..0000000
--- a/runtime/observatory/lib/src/elements/class_ref_as_value.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="class-ref-as-value">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .indented {
-        margin-left: 1.5em;
-        font: 400 14px 'Montserrat', sans-serif;
-        line-height: 150%;
-      }
-    </style><!--
-    --><class-ref ref="{{ ref }}"></class-ref><!--
-    --><curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
-        <div class="indented">
-          <template repeat="{{ field in ref.fields }}">
-            <template if="{{ field.isStatic }}">
-              {{ field.name }}&nbsp;:&nbsp;
-              <any-service-ref ref="{{ field.staticValue }}"
-                               expandKey="{{ makeExpandKey(field.name) }}">
-              </any-service-ref><br>
-            </template>
-          </template>
-        </div>
-      </curly-block><!--
-  --></template>
-</polymer-element>
-
-<script type="application/dart" src="class_ref_as_value.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/class_ref_wrapper.dart b/runtime/observatory/lib/src/elements/class_ref_wrapper.dart
deleted file mode 100644
index 8d9c3fc..0000000
--- a/runtime/observatory/lib/src/elements/class_ref_wrapper.dart
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service_html.dart' show Class;
-import 'package:observatory/src/elements/class_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class ClassRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<ClassRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<ClassRefElementWrapper>('class-ref');
-
-  Class _class;
-  Class get ref => _class;
-  void set ref(Class ref) {
-    _class = ref;
-    render();
-  }
-
-  ClassRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) return;
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        class-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        class-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new ClassRefElement(_class.isolate, _class,
-          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/class_tree.dart b/runtime/observatory/lib/src/elements/class_tree.dart
index 0e2aed0..5fb3328 100644
--- a/runtime/observatory/lib/src/elements/class_tree.dart
+++ b/runtime/observatory/lib/src/elements/class_tree.dart
@@ -9,12 +9,11 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/class_ref.dart';
 import 'package:observatory/src/elements/containers/virtual_tree.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/nav/vm_menu.dart';
@@ -23,9 +22,7 @@
 class ClassTreeElement extends HtmlElement implements Renderable{
   static const tag = const Tag<ClassTreeElement>('class-tree',
                      dependencies: const [ClassRefElement.tag,
-                                          NavBarElement.tag,
                                           NavIsolateMenuElement.tag,
-                                          NavMenuElement.tag,
                                           NavNotifyElement.tag,
                                           NavTopMenuElement.tag,
                                           NavVMMenuElement.tag,
@@ -84,15 +81,13 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('class hierarchy', link: Uris.classTree(_isolate),
-                             last: true, queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('class hierarchy'),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()
         ..classes = ['content-centered']
         ..children = [
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index 362aa9a..c87bee1 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -16,14 +16,13 @@
 import 'package:observatory/src/elements/field_ref.dart';
 import 'package:observatory/src/elements/function_ref.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
 import 'package:observatory/src/elements/library_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -45,12 +44,10 @@
                                                    FunctionRefElement.tag,
                                                    InstanceRefElement.tag,
                                                    LibraryRefElement.tag,
-                                                   NavBarElement.tag,
                                                    NavClassMenuElement.tag,
                                                    NavTopMenuElement.tag,
                                                    NavVMMenuElement.tag,
                                                    NavIsolateMenuElement.tag,
-                                                   NavMenuElement.tag,
                                                    NavRefreshElement.tag,
                                                    NavNotifyElement.tag,
                                                    ObjectCommonElement.tag,
@@ -178,30 +175,29 @@
       header += 'patch ';
     }
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavClassMenuElement(_isolate, _cls, queue: _r.queue),
-          new NavRefreshElement(label: 'Refresh Allocation Profile',
-                                queue: _r.queue)
-              ..onRefresh.listen((e) {
-                e.element.disabled = true;
-                _loadProfile = true;
-                _r.dirty();
-              }),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) {
-                e.element.disabled = true;
-                _common = null;
-                _classInstances = null;
-                _fieldsExpanded = null;
-                _functionsExpanded = null;
-                _refresh();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        new NavClassMenuElement(_isolate, _cls, queue: _r.queue),
+        new NavRefreshElement(label: 'Refresh Allocation Profile',
+                              queue: _r.queue)
+            ..onRefresh.listen((e) {
+              e.element.disabled = true;
+              _loadProfile = true;
+              _r.dirty();
+            }),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) {
+              e.element.disabled = true;
+              _common = null;
+              _classInstances = null;
+              _fieldsExpanded = null;
+              _functionsExpanded = null;
+              _refresh();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = '$header class ${_cls.name}',
@@ -408,7 +404,7 @@
               ..children =[
                 new CurlyBlockElement(expanded: _fieldsExpanded)
                   ..onToggle.listen((e) => _fieldsExpanded = e.control.expanded)
-                  ..children = [
+                  ..content = [
                     new DivElement()..classes = ['memberList']
                       ..children = (fields.map((f) =>
                         new DivElement()..classes = ['memberItem']
@@ -446,7 +442,7 @@
                 new CurlyBlockElement(expanded: _functionsExpanded)
                   ..onToggle.listen((e) =>
                       _functionsExpanded = e.control.expanded)
-                  ..children = (functions.map((f) =>
+                  ..content = (functions.map((f) =>
                     new DivElement()..classes = ['indent']
                       ..children = [
                         new FunctionRefElement(_isolate, f, queue: _r.queue)
diff --git a/runtime/observatory/lib/src/elements/code_ref.dart b/runtime/observatory/lib/src/elements/code_ref.dart
index 61917a8..c25f6c3 100644
--- a/runtime/observatory/lib/src/elements/code_ref.dart
+++ b/runtime/observatory/lib/src/elements/code_ref.dart
@@ -13,7 +13,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class CodeRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<CodeRefElement>('code-ref-wrapped');
+  static const tag = const Tag<CodeRefElement>('code-ref');
 
   RenderingScheduler<CodeRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/code_ref_wrapper.dart b/runtime/observatory/lib/src/elements/code_ref_wrapper.dart
deleted file mode 100644
index f630f33..0000000
--- a/runtime/observatory/lib/src/elements/code_ref_wrapper.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service_html.dart' show Code;
-import 'package:observatory/src/elements/code_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class CodeRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<CodeRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<CodeRefElementWrapper>('code-ref');
-
-  Code _code;
-
-  Code get ref => _code;
-
-  void set ref(Code value) {
-    _code = value;
-    render();
-  }
-
-  CodeRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        code-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        code-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new CodeRefElement(_code.isolate, _code,
-          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/code_view.dart b/runtime/observatory/lib/src/elements/code_view.dart
index 4ab070e..e342941 100644
--- a/runtime/observatory/lib/src/elements/code_view.dart
+++ b/runtime/observatory/lib/src/elements/code_view.dart
@@ -14,12 +14,12 @@
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/function_ref.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -41,12 +41,10 @@
                                             dependencies: const [
                                               CurlyBlockElement.tag,
                                               FunctionRefElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -194,24 +192,23 @@
     final inlinedFunctions = _code.inlinedFunctions.toList();
     final S.Code code = _code as S.Code;
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement(_code.name, last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _refresh();
-              }),
-          new NavRefreshElement(label: 'refresh ticks', queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _refreshTicks();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu(_code.name),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _refresh();
+            }),
+        new NavRefreshElement(label: 'refresh ticks', queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _refreshTicks();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h1()
@@ -290,7 +287,7 @@
                         new CurlyBlockElement(
                             expanded: inlinedFunctions.length < 8,
                             queue: _r.queue)
-                          ..children = inlinedFunctions.map((f) =>
+                          ..content = inlinedFunctions.map((f) =>
                             new FunctionRefElement(_isolate, f, queue: _r.queue)
                           ).toList()
                       ]
diff --git a/runtime/observatory/lib/src/elements/context_ref.dart b/runtime/observatory/lib/src/elements/context_ref.dart
index df1ae62..90138bb 100644
--- a/runtime/observatory/lib/src/elements/context_ref.dart
+++ b/runtime/observatory/lib/src/elements/context_ref.dart
@@ -11,7 +11,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class ContextRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<ContextRefElement>('context-ref-wrapped');
+  static const tag = const Tag<ContextRefElement>('context-ref');
 
   RenderingScheduler<ContextRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/context_ref_wrapper.dart b/runtime/observatory/lib/src/elements/context_ref_wrapper.dart
deleted file mode 100644
index 0f47f6f..0000000
--- a/runtime/observatory/lib/src/elements/context_ref_wrapper.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service_html.dart' show Context;
-import 'package:observatory/src/elements/context_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class ContextRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<ContextRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<ContextRefElementWrapper>('context-ref');
-
-  Context _context;
-  Context get ref => _context;
-  void set ref(Context ref) {
-    _context = ref;
-    render();
-  }
-
-  ContextRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) return;
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        context-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        context-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }
-        context-ref-wrapped .emphasize {
-          font-style: italic;
-        }''',
-      new ContextRefElement(_context.isolate, _context,
-          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/context_view.dart b/runtime/observatory/lib/src/elements/context_view.dart
index 7c7f9d1..c3afef5 100644
--- a/runtime/observatory/lib/src/elements/context_view.dart
+++ b/runtime/observatory/lib/src/elements/context_view.dart
@@ -8,12 +8,12 @@
 import 'package:observatory/src/elements/context_ref.dart';
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -26,12 +26,10 @@
                                             dependencies: const [
                                               ContextRefElement.tag,
                                               CurlyBlockElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -114,21 +112,20 @@
 
   void render() {
     var content = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavClassMenuElement(_isolate, _context.clazz, queue: _r.queue),
-          new NavMenuElement('instance', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _context = await _contexts.get(_isolate, _context.id);
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        new NavClassMenuElement(_isolate, _context.clazz, queue: _r.queue),
+        navMenu('instance'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _context = await _contexts.get(_isolate, _context.id);
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Context',
@@ -168,7 +165,7 @@
             new SpanElement()..text = 'Variables ',
             new CurlyBlockElement(expanded: _context.variables.length > 8,
                                   queue: _r.queue)
-              ..children = [
+              ..content = [
                 new DivElement()..classes = ['memberList']
                   ..children = _context.variables.map((variable)
                     => new DivElement()..classes = ['memberItem']
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 672f6d3..606c817 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -8,12 +8,12 @@
 import 'dart:html';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -24,11 +24,9 @@
 class CpuProfileElement  extends HtmlElement implements Renderable {
   static const tag = const Tag<CpuProfileElement>('cpu-profile',
                                             dependencies: const [
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               SampleBufferControlElement.tag,
@@ -96,19 +94,17 @@
 
   void render() {
     var content = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('cpu profile', link: Uris.cpuProfiler(_isolate),
-              last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen(_refresh),
-          new NavRefreshElement(label: 'Clear', queue: _r.queue)
-              ..onRefresh.listen(_clearCpuProfile),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('cpu profile', link: Uris.cpuProfiler(_isolate)),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen(_refresh),
+        new NavRefreshElement(label: 'Clear', queue: _r.queue)
+            ..onRefresh.listen(_clearCpuProfile),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
     ];
     if (_progress == null) {
       children = content;
diff --git a/runtime/observatory/lib/src/elements/cpu_profile_table.dart b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
index d841fc1..72be839 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile_table.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
@@ -10,12 +10,11 @@
 import 'package:observatory/src/elements/containers/virtual_collection.dart';
 import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
 import 'package:observatory/src/elements/function_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -47,11 +46,9 @@
   static const tag = const Tag<CpuProfileTableElement>('cpu-profile-table',
                                             dependencies: const [
                                               FunctionRefElement.tag,
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               SampleBufferControlElement.tag,
@@ -127,19 +124,17 @@
 
   void render() {
     var content = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('cpu profile (table)',
-              link: Uris.cpuProfilerTable(_isolate), last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen(_refresh),
-          new NavRefreshElement(label: 'Clear', queue: _r.queue)
-              ..onRefresh.listen(_clearCpuProfile),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('cpu profile (table)'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen(_refresh),
+        new NavRefreshElement(label: 'Clear', queue: _r.queue)
+            ..onRefresh.listen(_clearCpuProfile),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
     ];
     if (_progress == null) {
       children = content;
@@ -260,7 +255,7 @@
           _createHeaderButton(const ['name'], 'Method',
                               _Table.functions,
                               _SortingField.method,
-                              _SortingDirection.descending),
+                              _SortingDirection.ascending),
       ];
 
     void _setSorting(_Table table,
@@ -317,7 +312,7 @@
           _createHeaderButton(const ['name'], 'Method',
                               _Table.callee,
                               _SortingField.method,
-                              _SortingDirection.descending),
+                              _SortingDirection.ascending),
       ];
 
   Element _createCaller() {
@@ -355,7 +350,7 @@
           _createHeaderButton(const ['name'], 'Method',
                               _Table.caller,
                               _SortingField.method,
-                              _SortingDirection.descending),
+                              _SortingDirection.ascending),
       ];
 
   ButtonElement _createHeaderButton(List<String> classes,
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index 943cf8c..9e6defc 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -391,6 +391,18 @@
   direction: rtl;
 }
 
+allocation-profile .compactable {
+  position: relative;
+}
+
+allocation-profile .compact {
+  position: absolute;
+  bottom: 20px;
+  left: 50%;
+  width: 8em;
+  margin-left: -4em;
+}
+
 allocation-profile .heap-space.right * {
   direction: ltr;
   text-align: right;
@@ -437,6 +449,10 @@
   top: 560px;
 }
 
+allocation-profile .collection.expanded {
+  top: 160px;
+}
+
 allocation-profile .collection-item {
   box-sizing: border-box;
   line-height: 20px;
@@ -527,25 +543,21 @@
 }
 
 /* class-ref */
-/* TODO(cbernaschina) fix class-ref-wrapped to class-ref when wrapper
-removed */
 
-class-ref-wrapped > a[href]:hover {
+class-ref > a[href]:hover {
     text-decoration: underline;
 }
-class-ref-wrapped > a[href] {
+class-ref > a[href] {
     color: #0489c3;
     text-decoration: none;
 }
 
 /* code-ref */
-/* TODO(cbernaschina) fix code-ref-wrapped to code-ref when wrapper
-removed */
 
-code-ref-wrapped > a[href]:hover {
+code-ref > a[href]:hover {
   text-decoration: underline;
 }
-code-ref-wrapped > a[href] {
+code-ref > a[href] {
   color: #0489c3;
   text-decoration: none;
 }
@@ -627,17 +639,15 @@
 }
 
 /* context-ref */
-/* TODO(cbernaschina) fix context-ref-wrapped to context-ref when wrapper
-removed */
 
-context-ref-wrapped > a[href]:hover {
+context-ref > a[href]:hover {
     text-decoration: underline;
 }
-context-ref-wrapped > a[href] {
+context-ref > a[href] {
     color: #0489c3;
     text-decoration: none;
 }
-context-ref-wrapped > a[href] * {
+context-ref > a[href] * {
     color: inherit;
 }
 
@@ -825,11 +835,286 @@
   margin-left: 0.5em;
 }
 
-/* error-ref */
-/* TODO(cbernaschina) fix error-ref-wrapped to error-ref when wrapper
-removed */
+/* curly-block */
 
-error-ref-wrapped > pre {
+curly-block span.curly-block {
+  color: #0489c3;
+  cursor: pointer;
+}
+curly-block span.curly-block.disabled {
+  color: white;
+  cursor: wait;
+}
+
+/* debugger-console */
+
+debugger-console {
+  display: block;
+  margin: 0px 20px 10px 20px;
+}
+debugger-console .normal {
+  font: normal 14px consolas, courier, monospace;
+  white-space: pre;
+  line-height: 125%;
+}
+debugger-console .bold {
+  font: bold 14px consolas, courier, monospace;
+  white-space: pre;
+  line-height: 125%;
+}
+debugger-console .red {
+  font: normal 14px consolas, courier, monospace;
+  white-space: pre;
+  line-height: 125%;
+  color: red;
+}
+debugger-console .green {
+  font: normal 14px consolas, courier, monospace;
+  white-space: pre;
+  line-height: 125%;
+  color: green;
+}
+debugger-console .spacer {
+  height: 20px;
+}
+
+/* debugger-frame */
+
+debugger-frame {
+  display: block;
+  position: relative;
+  padding: 5px;
+  border: 1px solid white;
+}
+debugger-frame:hover {
+  border: 1px solid #e0e0e0;
+}
+debugger-frame.shadow {
+  box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.16),
+               0 2px 5px 0 rgba(0, 0, 0, 0.26);
+}
+debugger-frame.current {
+  box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.26),
+               0 2px 5px 0 rgba(0, 0, 0, 0.46);
+  border: 1px solid #444;
+}
+debugger-frame > button {
+  display: block;
+  width: 100%;
+  text-align: left;
+  background-color: transparent;
+  border: none;
+}
+debugger-frame .frameSummaryText {
+  display: inline-block;
+  padding: 5px;
+}
+debugger-frame .frameId {
+  display: inline-block;
+  width: 60px;
+}
+debugger-frame .frameExpander {
+  position: absolute;
+  right: 5px;
+  top: 5px;
+  display: none;
+}
+debugger-frame:hover .frameExpander{
+  display: inline-block;
+}
+debugger-frame .frameContractor {
+  position: absolute;
+  right: 5px;
+  bottom: 5px;
+  display: inline-block;
+}
+debugger-frame .frameContractor > button {
+  background-color: transparent;
+  border: none;
+}
+debugger-frame .flex-item-script {
+  flex-grow: 1;
+  flex-shrink: 1;
+  flex-basis: 765px;
+}
+debugger-frame .flex-item-vars {
+  flex-grow: 5;
+  flex-shrink: 0;
+  flex-basis: 250px;
+  overflow-x: hidden;
+}
+debugger-frame .frameVars {
+  position: relative;
+  top: 5px;
+  padding-left:2em;
+  padding-bottom: 5px;
+}
+
+/* debugger-input */
+
+debugger-input .container {
+  height: 100%;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+}
+debugger-input .textBox {
+  flex: 1 1 auto;
+  margin: 20px;
+  padding: 5px;
+  font: 400 16px consolas, courier, monospace;
+  width: 95%;
+}
+debugger-input .modalPrompt {
+  flex: 0 0 auto;
+  margin-top: 20px;
+  margin-left: 20px;
+  padding: 5px;
+  font: 400 16px consolas, courier, monospace;
+  color: red;
+}
+debugger-input .modalPrompt.hidden {
+  display: none;
+}
+
+/* debugger-message */
+
+debugger-message {
+  display: block;
+  position: relative;
+  padding: 5px;
+  border: 1px solid white;
+}
+debugger-message:hover {
+  border: 1px solid #e0e0e0;
+}
+debugger-message.shadow {
+  box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.16),
+  0 2px 5px 0 rgba(0, 0, 0, 0.26);
+}
+debugger-message.current {
+  box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.26),
+  0 2px 5px 0 rgba(0, 0, 0, 0.46);
+  border: 1px solid #444;
+}
+debugger-message > button {
+  display: block;
+  width: 100%;
+  text-align: left;
+  background-color: transparent;
+  border: none;
+}
+debugger-message .messageSummaryText {
+  display: inline-block;
+  padding: 5px;
+}
+debugger-message .messageId {
+  display: inline-block;
+  font-weight: bold;
+  width: 100px;
+}
+debugger-message .messageExpander {
+  position: absolute;
+  right: 5px;
+  top: 5px;
+  display: none;
+}
+debugger-message:hover .messageExpander {
+  display: inline-block;
+}
+debugger-message.shadow:hover .messageExpander {
+  display: none;
+}
+debugger-message .messageContractor {
+  position: absolute;
+  right: 5px;
+  bottom: 5px;
+  display: inline-block;
+}
+debugger-message .flex-item-script {
+  flex-grow: 1;
+  flex-shrink: 1;
+  flex-basis: 765px;
+}
+debugger-message .flex-item-vars {
+  flex-grow: 5;
+  flex-shrink: 0;
+  flex-basis: 225px;
+}
+
+/* debugger-page */
+
+debugger-page {
+  height: 100%;
+}
+debugger-page .variable {
+  height: 100%;
+  margin-bottom: -75px;
+  padding-bottom: 75px;
+}
+debugger-page .stack {
+  flex: 0 0 auto;
+  overflow-y: auto;
+  height: 62%;
+}
+debugger-page .splitter {
+  height: 0px;
+  margin: 0px;
+  font-size: 1px;
+  border-bottom: 1px solid #888;
+}
+debugger-page .console {
+  flex: 1 1 auto;
+  overflow-x: auto;
+  overflow-y: auto;
+  height: 38%;
+}
+debugger-page .commandline {
+  flex: 0 0 auto;
+}
+
+/* debugger-stack */
+
+debugger-stack {
+  position: relative;
+}
+debugger-stack .sampledMessage {
+  margin: 0px 20px 10px 20px;
+  font: 400 14px 'Montserrat', sans-serif;
+  line-height: 125%;
+}
+debugger-stack .sampledMessage > button {
+  background-color: transparent;
+  border: none;
+  color: #0489c3;
+  text-decoration: none;
+  margin-right: 1em;
+}
+debugger-stack .sampledMessage > button:hover {
+    text-decoration: underline;
+}
+debugger-stack .splitter {
+  height: 0px;
+  margin: 0px;
+  font-size: 1px;
+  border-bottom: 1px dashed #888;
+}
+debugger-stack .noMessages,
+debugger-stack .noStack {
+  margin: 10px 0px 10px 25px;
+  font: bold 14px 'Montserrat', sans-serif;
+  line-height: 125%;
+}
+
+debugger-stack .sampledMessage.hidden,
+debugger-stack .noMessages.hidden,
+debugger-stack .noStack.hidden {
+  display: none;
+}
+
+/* error-ref */
+
+error-ref > pre {
   background-color: #f5f5f5;
   border: 1px solid #ccc;
   padding-left: 10px;
@@ -841,22 +1126,20 @@
 }
 
 /* eval-box */
-/* TODO(cbernaschina) fix eval-box-wrapped to error-ref when wrapper
-removed */
 
-eval-box-wrapped a[href]:hover {
+eval-box a[href]:hover {
     text-decoration: underline;
 }
-eval-box-wrapped a[href] {
+eval-box a[href] {
     color: #0489c3;
     text-decoration: none;
 }
-eval-box-wrapped .quicks > button:hover {
+eval-box .quicks > button:hover {
   background-color: transparent;
   border: none;
   text-decoration: underline;
 }
-eval-box-wrapped .quicks > button {
+eval-box .quicks > button {
   background-color: transparent;
   border: none;
   color: #0489c3;
@@ -864,15 +1147,15 @@
   margin-right: 1em;
   text-decoration: none;
 }
-eval-box-wrapped .emphasize {
+eval-box .emphasize {
   font-style: italic;
 }
-eval-box-wrapped .indent {
+eval-box .indent {
   margin-left: 1.5em;
   font: 400 14px 'Montserrat', sans-serif;
   line-height: 150%;
 }
-eval-box-wrapped .stackTraceBox {
+eval-box .stackTraceBox {
   margin-left: 1.5em;
   background-color: #f5f5f5;
   border: 1px solid #ccc;
@@ -882,7 +1165,7 @@
   white-space: pre;
   overflow-x: auto;
 }
-eval-box-wrapped .heading {
+eval-box .heading {
   line-height: 30px;
   position: relative;
   box-sizing: border-box;
@@ -890,24 +1173,24 @@
   min-width: 450px;
   padding-right: 150px;
 }
-eval-box-wrapped .heading .textbox {
+eval-box .heading .textbox {
   width: 100%;
   min-width: 300px;
 }
-eval-box-wrapped .heading .buttons {
+eval-box .heading .buttons {
   position: absolute;
   top: 0;
   right: 0px;
 }
-eval-box-wrapped .heading .buttons button{
+eval-box .heading .buttons button{
   margin-right: 1em;
 }
-eval-box-wrapped.historyExpr,
-eval-box-wrapped .historyValue {
+eval-box.historyExpr,
+eval-box .historyValue {
   vertical-align: text-top;
   font: 400 14px 'Montserrat', sans-serif;
 }
-eval-box-wrapped .historyExpr button {
+eval-box .historyExpr button {
   display: block;
   color: black;
   border: none;
@@ -917,18 +1200,18 @@
   cursor: pointer;
   white-space: pre-line;
 }
-eval-box-wrapped .historyExpr button:hover {
+eval-box .historyExpr button:hover {
   background-color: #fff3e3;
 }
-eval-box-wrapped .historyValue {
+eval-box .historyValue {
   display: block;
   padding: 6px 6px;
 }
-eval-box-wrapped .historyDelete button {
+eval-box .historyDelete button {
   border: none;
   background: none;
 }
-eval-box-wrapped .historyDelete button:hover {
+eval-box .historyDelete button:hover {
   color: #BB3311;
 }
 
@@ -952,13 +1235,11 @@
 }
 
 /* function-ref */
-/* TODO(cbernaschina) fix function-ref-wrapped to function-ref when wrapper
-removed */
 
-function-ref-wrapped > a[href]:hover {
+function-ref > a[href]:hover {
   text-decoration: underline;
 }
-function-ref-wrapped > a[href] {
+function-ref > a[href] {
   color: #0489c3;
   text-decoration: none;
 }
@@ -1054,28 +1335,26 @@
 }
 
 /* instance-ref */
-/* TODO(cbernaschina) fix instance-ref-wrapped to instance-ref when wrapper
-removed */
 
-instance-ref-wrapped > a[href]:hover {
+instance-ref > a[href]:hover {
   text-decoration: underline;
 }
-instance-ref-wrapped > a[href] {
+instance-ref > a[href] {
   color: #0489c3;
   text-decoration: none;
 }
-instance-ref-wrapped > a[href] * {
+instance-ref > a[href] * {
   color: inherit;
 }
-instance-ref-wrapped .emphasize {
+instance-ref .emphasize {
   font-style: italic;
 }
-instance-ref-wrapped .indent {
+instance-ref .indent {
   margin-left: 1.5em;
   font: 400 14px 'Montserrat', sans-serif;
   line-height: 150%;
 }
-instance-ref-wrapped .stackTraceBox {
+instance-ref .stackTraceBox {
   margin-left: 1.5em;
   background-color: #f5f5f5;
   border: 1px solid #ccc;
@@ -1130,13 +1409,11 @@
 }
 
 /* isolate-ref */
-/* TODO(cbernaschina) fix isolate-ref-wrapped to isolate-ref when wrapper
-removed */
 
-isolate-ref-wrapped > a[href]:hover {
+isolate-ref > a[href]:hover {
   text-decoration: underline;
 }
-isolate-ref-wrapped > a[href] {
+isolate-ref > a[href] {
   color: #0489c3;
   text-decoration: none;
 }
@@ -1179,13 +1456,11 @@
 }
 
 /* library-ref */
-/* TODO(cbernaschina) fix library-ref-wrapped to library-ref when wrapper
-removed */
 
-library-ref-wrapped > a[href]:hover {
+library-ref > a[href]:hover {
   text-decoration: underline;
 }
-library-ref-wrapped > a[href] {
+library-ref > a[href] {
   color: #0489c3;
   text-decoration: none;
 }
@@ -1249,27 +1524,159 @@
 }
 
 /* megamorphic-cache-ref */
-/* TODO(cbernaschina) fix megamorphic-cache-ref-wrapped to megamorphic-cache-ref
-when wrapper removed */
 
-megamorphic-cache-ref-wrapped > a[href]:hover {
+megamorphic-cache-ref > a[href]:hover {
     text-decoration: underline;
 }
-megamorphic-cache-ref-wrapped > a[href] {
+megamorphic-cache-ref > a[href] {
     color: #0489c3;
     text-decoration: none;
 }
-megamorphic-cache-ref-wrapped > a[href] * {
+megamorphic-cache-ref > a[href] * {
     color: inherit;
 }
 
+/* metric-graph */
+
+metric-graph {
+  display: block;
+  height: 100%;
+}
+
+metric-graph .graph {
+  height: 100%;
+  margin-top: -30px;
+  padding: 20px;
+  padding-top: 60px;
+}
+
+metric-graph .graph > div {
+  height: 100%;
+}
+
+/* metric-graph */
+
+metrics-page > div {
+  display: block;
+  height: 100%;
+}
+
+metrics-page > div > .graph {
+  display: block;
+  height: 100%;
+  margin-top: -300px;
+  padding-top: 300px;
+}
+
+/* nav-bar */
+
+nav.nav-bar {
+  line-height: normal;
+  position: fixed;
+  top: 0;
+  width: 100%;
+  z-index: 1000;
+}
+nav.nav-bar > ul {
+  display: inline-table;
+  position: relative;
+  list-style: none;
+  padding-left: 0;
+  margin: 0;
+  width: 100%;
+  z-index: 1000;
+  font: 400 16px 'Montserrat', sans-serif;
+  color: white;
+  background-color: #0489c3;
+}
+
+/* nav-menu */
+li.nav-menu:before {
+  display: inline-block;
+  content: '>';
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+}
+nav.nav-bar > ul *:first-child li.nav-menu:before {
+  content: '';
+  margin-left: 0;
+  margin-right: 0;
+}
+li.nav-menu, .nav-menu_label {
+  display: inline-block;
+}
+.nav-menu_label > a {
+  display: inline-block;
+  padding: 12px 8px;
+  color: White;
+  text-decoration: none;
+}
+.nav-menu_label:hover > a {
+  background: #455;
+}
+.nav-menu_label > ul {
+  display: none;
+  position: absolute;
+  top: 98%;
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  width: auto;
+  z-index: 1000;
+  font: 400 16px 'Montserrat', sans-serif;
+  color: white;
+  background: #567;
+}
+.nav-menu_label > ul:after {
+  content: ""; clear: both; display: block;
+}
+.nav-menu_label:hover > ul {
+  display: block;
+}
+
+/* nav-menu-item */
+
+nav-menu-item li.nav-menu-item {
+  float: none;
+  border-top: 1px solid #677;
+  border-bottom: 1px solid #556; position: relative;
+}
+nav-menu-item li.nav-menu-item:hover {
+  background: #455;
+}
+nav-menu-item li.nav-menu-item > a {
+  display: block;
+  padding: 12px 12px;
+  color: white;
+  text-decoration: none;
+}
+nav-menu-item li.nav-menu-item > ul {
+  display: none;
+  position: absolute;
+  top:0;
+  left: 100%;
+  list-style: none;
+  padding: 0;
+  margin-left: 0;
+  width: auto;
+  z-index: 1000;
+  font: 400 16px 'Montserrat', sans-serif;
+  color: white;
+  background: #567;
+}
+nav-menu-item li.nav-menu-item > ul:after {
+  content: ""; clear: both; display: block;
+}
+nav-menu-item li.nav-menu-item:hover > ul {
+  display: block;
+}
+
 /* nav-notify */
-/* TODO(cbernaschina) fix nav-notify-wrapped to nav-notify when wrapper
-removed */
-nav-notify-wrapped > div {
+
+nav-notify > div {
   float: right;
 }
-nav-notify-wrapped > div > div {
+nav-notify > div > div {
   display: block;
   position: absolute;
   top: 98%;
@@ -1303,12 +1710,14 @@
   font-size: 12px;
 }
 
-nav-exception > div > a, nav-event > div > a {
+nav-exception > div > a[href],
+nav-event > div > a[href] {
   color: white;
   text-decoration: none;
 }
 
-nav-exception > div > a:hover, nav-event > div > a:hover {
+nav-exception > div > a[href]:hover,
+nav-event > div > a[href]:hover {
   text-decoration: underline;
 }
 
@@ -1339,10 +1748,8 @@
 }
 
 /* nav-refresh */
-/* TODO(cbernaschina) fix nav-refresh-wrapped to nav-refresh when wrapper
-removed */
 
-nav-refresh-wrapped > li > button {
+nav-refresh > li > button {
   color: #000;
   margin: 3px;
   padding: 8px;
@@ -1351,27 +1758,25 @@
   font-size: 13px;
   font: 400 'Montserrat', sans-serif;
 }
-nav-refresh-wrapped > li > button[disabled] {
+nav-refresh > li > button[disabled] {
   color: #aaa;
   cursor: wait;
 }
-nav-refresh-wrapped > li {
+nav-refresh > li {
   float: right;
   margin: 0;
 }
 
 /* object-common && class-instances */
-/* TODO(cbernaschina) fix object-common-wrapped to object-common when wrapper
-removed */
 
 class-instances button:hover,
-object-common-wrapped button:hover {
+object-common button:hover {
   background-color: transparent;
   border: none;
   text-decoration: underline;
 }
 class-instances button,
-object-common-wrapped button {
+object-common button {
   background-color: transparent;
   border: none;
   color: #0489c3;
@@ -1484,27 +1889,23 @@
 }
 
 /* script-ref */
-/* TODO(cbernaschina) fix script-ref-wrapped to script-ref when wrapper
-removed */
 
-script-ref-wrapped > a[href]:hover {
+script-ref > a[href]:hover {
     text-decoration: underline;
 }
 
-script-ref-wrapped > a[href] {
+script-ref > a[href] {
     color: #0489c3;
     text-decoration: none;
 }
 
 /* source-link */
-/* TODO(cbernaschina) fix source-link-wrapped to source-link when wrapper
-removed */
 
-source-link-wrapped > a[href]:hover {
+source-link > a[href]:hover {
     text-decoration: underline;
 }
 
-source-link-wrapped > a[href] {
+source-link > a[href] {
     color: #0489c3;
     text-decoration: none;
 }
@@ -1557,14 +1958,12 @@
 }
 
 /* script-inset */
-/* TODO(cbernaschina) fix script-inset-wrapped to script-inset when wrapper
-removed */
 
-script-inset-wrapped {
+script-inset {
   position: relative;
 }
-script-inset-wrapped button.refresh,
-script-inset-wrapped button.toggle-profile {
+script-inset button.refresh,
+script-inset button.toggle-profile {
   background-color: transparent;
   padding: 0;
   margin: 0;
@@ -1576,27 +1975,27 @@
   line-height: 30px;
   font: 400 20px 'Montserrat', sans-serif;
 }
-script-inset-wrapped button.refresh {
+script-inset button.refresh {
   right: 5px;
   font-size: 25px;
 }
-script-inset-wrapped button.toggle-profile {
+script-inset button.toggle-profile {
   right: 30px;
   font-size: 20px;
 }
-script-inset-wrapped button.toggle-profile.enabled {
+script-inset button.toggle-profile.enabled {
   color: #BB3322;
 }
-script-inset-wrapped a {
+script-inset a {
   color: #0489c3;
   text-decoration: none;
 }
-script-inset-wrapped a:hover {
+script-inset a:hover {
   text-decoration: underline;
 }
-script-inset-wrapped .sourceInset {
+script-inset .sourceInset {
 }
-script-inset-wrapped .sourceTable {
+script-inset .sourceTable {
   position: relative;
   background-color: #f5f5f5;
   border: 1px solid #ccc;
@@ -1605,31 +2004,31 @@
   box-sizing: border-box;
   overflow-x: scroll;
 }
-script-inset-wrapped .sourceRow {
+script-inset .sourceRow {
   display: flex;
   flex-direction: row;
   width: 100%;
 }
-script-inset-wrapped .sourceItem,
-script-inset-wrapped .sourceItemCurrent {
+script-inset .sourceItem,
+script-inset .sourceItemCurrent {
   vertical-align: top;
   font: 400 14px consolas, courier, monospace;
   line-height: 125%;
   white-space: pre;
   max-width: 0;
 }
-script-inset-wrapped .currentLine {
+script-inset .currentLine {
   background-color: #fff;
 }
-script-inset-wrapped .currentCol {
+script-inset .currentCol {
   background-color: #6cf;
 }
-script-inset-wrapped .hitsCurrent,
-script-inset-wrapped .hitsNone,
-script-inset-wrapped .hitsNotExecuted,
-script-inset-wrapped .hitsExecuted,
-script-inset-wrapped .hitsCompiled,
-script-inset-wrapped .hitsNotCompiled {
+script-inset .hitsCurrent,
+script-inset .hitsNone,
+script-inset .hitsNotExecuted,
+script-inset .hitsExecuted,
+script-inset .hitsCompiled,
+script-inset .hitsNotCompiled {
   display: table-cell;
   vertical-align: top;
   font: 400 14px consolas, courier, monospace;
@@ -1638,28 +2037,28 @@
   text-align: right;
   color: #a8a8a8;
 }
-script-inset-wrapped .hitsCurrent {
+script-inset .hitsCurrent {
   background-color: #6cf;
   color: black;
 }
-script-inset-wrapped .hitsNotExecuted {
+script-inset .hitsNotExecuted {
   background-color: #faa;
 }
-script-inset-wrapped .hitsExecuted {
+script-inset .hitsExecuted {
   background-color: #aea;
 }
-script-inset-wrapped .hitsCompiled {
+script-inset .hitsCompiled {
   background-color: #e0e0e0;
 }
-script-inset-wrapped .hitsNotCompiled {
+script-inset .hitsNotCompiled {
   background-color: #f0c5c5;
 }
-script-inset-wrapped .noCopy {}
-script-inset-wrapped .emptyBreakpoint,
-script-inset-wrapped .possibleBreakpoint,
-script-inset-wrapped .busyBreakpoint,
-script-inset-wrapped .unresolvedBreakpoint,
-script-inset-wrapped .resolvedBreakpoint  {
+script-inset .noCopy {}
+script-inset .emptyBreakpoint,
+script-inset .possibleBreakpoint,
+script-inset .busyBreakpoint,
+script-inset .unresolvedBreakpoint,
+script-inset .resolvedBreakpoint  {
   display: table-cell;
   vertical-align: top;
   font: 400 14px consolas, courier, monospace;
@@ -1667,39 +2066,39 @@
   text-align: center;
   cursor: pointer;
 }
-script-inset-wrapped .possibleBreakpoint {
+script-inset .possibleBreakpoint {
   color: #e0e0e0;
 }
-script-inset-wrapped .possibleBreakpoint:hover {
+script-inset .possibleBreakpoint:hover {
   color: white;
   background-color: #777;
 }
-script-inset-wrapped .busyBreakpoint {
+script-inset .busyBreakpoint {
   color: white;
   background-color: black;
   cursor: wait;
 }
-script-inset-wrapped .unresolvedBreakpoint {
+script-inset .unresolvedBreakpoint {
   color: white;
   background-color: #cac;
 }
-script-inset-wrapped .resolvedBreakpoint {
+script-inset .resolvedBreakpoint {
   color: white;
   background-color: #e66;
 }
-script-inset-wrapped .unresolvedBreakAnnotation {
+script-inset .unresolvedBreakAnnotation {
   color: white;
   background-color: #cac;
 }
-script-inset-wrapped .resolvedBreakAnnotation {
+script-inset .resolvedBreakAnnotation {
   color: white;
   background-color: #e66;
 }
-script-inset-wrapped .notSourceProfile,
-script-inset-wrapped .noProfile,
-script-inset-wrapped .coldProfile,
-script-inset-wrapped .mediumProfile,
-script-inset-wrapped .hotProfile {
+script-inset .notSourceProfile,
+script-inset .noProfile,
+script-inset .coldProfile,
+script-inset .mediumProfile,
+script-inset .hotProfile {
   display: table-cell;
   vertical-align: top;
   font: 400 14px consolas, courier, monospace;
@@ -1709,18 +2108,18 @@
   margin-left: 5px;
   margin-right: 5px;
 }
-script-inset-wrapped .notSourceProfile {
+script-inset .notSourceProfile {
 }
-script-inset-wrapped .noProfile {
+script-inset .noProfile {
   background-color: #e0e0e0;
 }
-script-inset-wrapped .coldProfile {
+script-inset .coldProfile {
   background-color: #aea;
 }
-script-inset-wrapped .mediumProfile {
+script-inset .mediumProfile {
   background-color: #fe9;
 }
-script-inset-wrapped .hotProfile {
+script-inset .hotProfile {
   background-color: #faa;
 }
 
diff --git a/runtime/observatory/lib/src/elements/curly_block.dart b/runtime/observatory/lib/src/elements/curly_block.dart
index 9eadd76..54e0d3f 100644
--- a/runtime/observatory/lib/src/elements/curly_block.dart
+++ b/runtime/observatory/lib/src/elements/curly_block.dart
@@ -16,20 +16,7 @@
 }
 
 class CurlyBlockElement extends HtmlElement implements Renderable {
-  static final StyleElement _style = () {
-      var style = new StyleElement();
-      style.text = '''span.curly-block {
-                        color: #0489c3;
-                        cursor: pointer;
-                      }
-                      span.curly-block.disabled {
-                        color: white;
-                        cursor: wait;
-                      }''';
-      return style;
-  }();
-
-  static const tag = const Tag<CurlyBlockElement>('curly-block-wrapped');
+  static const tag = const Tag<CurlyBlockElement>('curly-block');
 
   RenderingScheduler<CurlyBlockElement> _r;
 
@@ -40,14 +27,21 @@
 
   bool _expanded;
   bool _disabled;
+  Iterable<Element> _content = const [];
 
   bool get expanded => _expanded;
+  bool get disabled => _disabled;
+  Iterable<Element> get content => _content;
+
   set expanded(bool value) {
     if (_expanded != value) _onToggle.add(new CurlyBlockToggleEvent(this));
     _expanded = _r.checkAndReact(_expanded, value);
   }
-  bool get disabled => _disabled;
   set disabled(bool value) => _disabled = _r.checkAndReact(_disabled, value);
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
 
   factory CurlyBlockElement({bool expanded: false, bool disabled: false,
       RenderingQueue queue}) {
@@ -57,10 +51,11 @@
     e._r = new RenderingScheduler(e, queue: queue);
     e._expanded = expanded;
     e._disabled = disabled;
+    e._r.enable();
     return e;
   }
 
-  CurlyBlockElement.created() : super.created() { createShadowRoot(); }
+  CurlyBlockElement.created() : super.created();
 
   @override
   void attached() { super.attached(); _r.enable(); }
@@ -68,7 +63,7 @@
   @override
   void detached() {
     super.detached(); _r.disable(notify: true);
-    shadowRoot.children = [];
+    children = [];
   }
 
   void toggle() {
@@ -80,8 +75,7 @@
   }
 
   void render() {
-    List<Element> children = [
-      _style.clone(true),
+    List<Element> content = [
       new SpanElement()..text = '{'
     ];
     SpanElement label = new SpanElement()
@@ -89,19 +83,17 @@
       ..innerHtml = expanded ?
         '&nbsp;&nbsp;&#8863;&nbsp;&nbsp;' : '&nbsp;&nbsp;&#8862;&nbsp;&nbsp;';
     if (disabled) {
-      children.add(label);
+      content.add(label);
     } else {
-      children.add(new AnchorElement()
+      content.add(new AnchorElement()
         ..onClick.listen((_) { toggle(); })
         ..children = [label]);
     }
     if (expanded) {
-      children.addAll([
-        new BRElement(),
-        new ContentElement()
-      ]);
+      content.add(new BRElement());
+      content.addAll(_content);
     }
-    children.add(new SpanElement()..text = '}');
-    shadowRoot.children = children;
+    content.add(new SpanElement()..text = '}');
+    children = content;
   }
 }
diff --git a/runtime/observatory/lib/src/elements/curly_block_wrapper.dart b/runtime/observatory/lib/src/elements/curly_block_wrapper.dart
deleted file mode 100644
index 4e2519a..0000000
--- a/runtime/observatory/lib/src/elements/curly_block_wrapper.dart
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/src/elements/curly_block.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-typedef _callback();
-typedef CurlyBlockToggleCallback(bool a, _callback b);
-
-@bindable
-class CurlyBlockElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<CurlyBlockElementWrapper>(const {
-      'expand': #expand, 'busy': #busy, 'expandKey': #expandKey,
-      'callback': #callback
-    });
-
-  static const tag = const Tag<CurlyBlockElementWrapper>('curly-block');
-
-  bool _expand;
-  bool get expand => _expand;
-  set expand(bool expanded) {
-    _expand = !(expanded == null || expanded == false);
-    render();
-  }
-
-  bool _busy;
-  bool get busy => _busy;
-  set busy(bool busy) {
-    _busy = !(busy == null || busy == false);
-    render();
-  }
-
-  String _expandKey;
-  String get expandKey => _expandKey;
-  set expandKey(String expandKey) {
-    _expandKey = expandKey;
-    if (expandKey != null) {
-      var value = application.expansions[expandKey];
-      if (value != null && expand != value) {
-
-      }
-    }
-    render();
-  }
-
-  CurlyBlockToggleCallback _callback;
-  CurlyBlockToggleCallback get callback => _callback;
-  set callback(CurlyBlockToggleCallback callback) {
-    _callback = callback;
-    render();
-  }
-
-  CurlyBlockElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    _expand = !_isFalseOrNull(getAttribute('expand'));
-    _busy = !_isFalseOrNull(getAttribute('busy'));
-    _expandKey = getAttribute('expandKey');
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [
-      new CurlyBlockElement(expanded: expand, disabled: busy,
-                                 queue: ObservatoryApplication.app.queue)
-        ..children = [new ContentElement()]
-        ..onToggle.listen(_toggle)
-    ];
-  }
-
-  ObservatoryApplication get application => ObservatoryApplication.app;
-
-  void _toggle(CurlyBlockToggleEvent e) {
-    _expand = e.control.expanded;
-    if (callback != null) {
-      busy = true;
-      callback(expand, () {
-        if (expandKey != null) {
-          application.expansions[expandKey] = expand;
-        }
-        busy = false;
-      });
-    } else {
-      application.expansions[expandKey] = expand;
-    }
-  }
-
-  bool _isFalseOrNull(String value) {
-    return value == null || value == false;
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 9bd4eff..dc5f443 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -5,17 +5,30 @@
 library debugger_page_element;
 
 import 'dart:async';
+import 'dart:svg';
 import 'dart:html';
 import 'dart:math';
-import 'observatory_element.dart';
 import 'package:observatory/event.dart';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/app.dart';
 import 'package:observatory/cli.dart';
 import 'package:observatory/debugger.dart';
-import 'package:observatory/service.dart';
+import 'package:observatory/src/elements/function_ref.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/instance_ref.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/source_inset.dart';
+import 'package:observatory/src/elements/source_link.dart';
+import 'package:observatory/service.dart' as S;
 import 'package:logging/logging.dart';
-import 'package:polymer/polymer.dart';
 
 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library.
 abstract class DebuggerCommand extends Command {
@@ -161,11 +174,11 @@
     var expression = args.join('');
     var response = await debugger.isolate.evalFrame(debugger.currentFrame,
                                                     expression);
-    if (response is DartError) {
+    if (response is S.DartError) {
       debugger.console.print(response.message);
     } else {
       debugger.console.print('= ', newline:false);
-      debugger.console.printRef(response);
+      debugger.console.printRef(debugger.isolate, response, debugger.instances);
     }
   }
 
@@ -648,8 +661,8 @@
       if (loc.function != null) {
         try {
           await debugger.isolate.addBreakpointAtEntry(loc.function);
-        } on ServerRpcException catch(e) {
-          if (e.code == ServerRpcException.kCannotAddBreakpoint) {
+        } on S.ServerRpcException catch(e) {
+          if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
             debugger.console.print('Unable to set breakpoint at ${loc}');
           } else {
             rethrow;
@@ -666,8 +679,8 @@
         }
         try {
           await debugger.isolate.addBreakpoint(script, loc.line, loc.col);
-        } on ServerRpcException catch(e) {
-          if (e.code == ServerRpcException.kCannotAddBreakpoint) {
+        } on S.ServerRpcException catch(e) {
+          if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
             debugger.console.print('Unable to set breakpoint at ${loc}');
           } else {
             rethrow;
@@ -756,7 +769,7 @@
             loc.col == script.tokenToCol(bpt.location.tokenPos)) {
           foundBreakpoint = true;
           var result = await debugger.isolate.removeBreakpoint(bpt);
-          if (result is DartError) {
+          if (result is S.DartError) {
             debugger.console.print(
                 'Error clearing breakpoint ${bpt.number}: ${result.message}');
           }
@@ -938,9 +951,7 @@
         debugger.console.print(
             "Current isolate is already ${candidate.number} '${candidate.name}'");
       } else {
-        debugger.console.print(
-            "Switching to isolate ${candidate.number} '${candidate.name}'");
-        debugger.isolate = candidate;
+        new AnchorElement(href: Uris.debugger(candidate)).click();
       }
     }
     return new Future.value(null);
@@ -973,7 +984,7 @@
       '        isolate <name>\n';
 }
 
-String _isolateRunState(Isolate isolate) {
+String _isolateRunState(S.Isolate isolate) {
   if (isolate.paused) {
     return 'paused';
   } else if (isolate.running) {
@@ -1248,8 +1259,8 @@
   String _savedLine;
   List<String> _buffer = [];
 
-  void onEvent(String streamName, ServiceEvent event) {
-    if (event.kind == ServiceEvent.kLogging) {
+  void onEvent(String streamName, S.ServiceEvent event) {
+    if (event.kind == S.ServiceEvent.kLogging) {
       // Check if we should print this log message.
       if (event.logRecord['level'].value < _minimumLogLevel.value) {
         return;
@@ -1264,7 +1275,7 @@
     }
     String data;
     bool hasNewline;
-    if (event.kind == ServiceEvent.kLogging) {
+    if (event.kind == S.ServiceEvent.kLogging) {
       data = event.logRecord["message"].valueAsString;
       hasNewline = true;
     } else {
@@ -1320,7 +1331,8 @@
   DebuggerConsoleElement console;
   DebuggerInputElement input;
   DebuggerStackElement stackElement;
-  ServiceMap stack;
+  S.ServiceMap stack;
+  final S.Isolate isolate;
   String breakOnException = "none";  // Last known setting.
 
   int get currentFrame => _currentFrame;
@@ -1361,7 +1373,9 @@
 
   int get stackDepth => stack['frames'].length;
 
-  ObservatoryDebugger() {
+  static final _history = [''];
+
+  ObservatoryDebugger(this.isolate) {
     _loadSettings();
     cmd = new RootCommand([
         new AsyncNextCommand(this),
@@ -1386,7 +1400,7 @@
         new SyncNextCommand(this),
         new UpCommand(this),
         new VmCommand(this),
-    ]);
+    ], _history);
     _consolePrinter = new _ConsoleStreamPrinter(this);
   }
 
@@ -1394,55 +1408,12 @@
     _upIsDown = settings.get('up-is-down');
   }
 
-  VM get vm => page.app.vm;
-
-  void updateIsolate(Isolate iso) {
-    _isolate = iso;
-    if (_isolate != null) {
-      if ((breakOnException != iso.exceptionsPauseInfo) &&
-          (iso.exceptionsPauseInfo != null)) {
-        breakOnException = iso.exceptionsPauseInfo;
-      }
-
-      _isolate.reload().then((response) {
-        if (response.isSentinel) {
-          // The isolate has gone away.  The IsolateExit event will
-          // clear the isolate for the debugger page.
-          return;
-        }
-        // TODO(turnidge): Currently the debugger relies on all libs
-        // being loaded.  Fix this.
-        var pending = [];
-        for (var lib in response.libraries) {
-          if (!lib.loaded) {
-            pending.add(lib.load());
-          }
-        }
-        Future.wait(pending).then((_) {
-          refreshStack();
-        }).catchError((e) {
-          print("UNEXPECTED ERROR $e");
-          reportStatus();
-        });
-      });
-    } else {
-      reportStatus();
-    }
-  }
-
-  set isolate(Isolate iso) {
-    // Setting the page's isolate will trigger updateIsolate to be called.
-    //
-    // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another
-    // change.
-    page.isolate = iso;
-  }
-  Isolate get isolate => _isolate;
-  Isolate _isolate;
+  S.VM get vm => page.app.vm;
 
   void init() {
-    console.newline();
-    console.printBold("Type 'h' for help");
+    console.printBold('Debugging isolate isolate ${isolate.number} '
+                      '\'${isolate.name}\' ');
+    console.printBold('Type \'h\' for help');
     // Wait a bit and if polymer still hasn't set up the isolate,
     // report this to the user.
     new Timer(const Duration(seconds:1), () {
@@ -1450,12 +1421,39 @@
         reportStatus();
       }
     });
+
+    if ((breakOnException != isolate.exceptionsPauseInfo) &&
+        (isolate.exceptionsPauseInfo != null)) {
+      breakOnException = isolate.exceptionsPauseInfo;
+    }
+
+    isolate.reload().then((response) {
+      if (response.isSentinel) {
+        // The isolate has gone away.  The IsolateExit event will
+        // clear the isolate for the debugger page.
+        return;
+      }
+      // TODO(turnidge): Currently the debugger relies on all libs
+      // being loaded.  Fix this.
+      var pending = [];
+      for (var lib in response.libraries) {
+        if (!lib.loaded) {
+          pending.add(lib.load());
+        }
+      }
+      Future.wait(pending).then((_) {
+        refreshStack();
+      }).catchError((e) {
+        print("UNEXPECTED ERROR $e");
+        reportStatus();
+      });
+    });
   }
 
   Future refreshStack() async {
     try {
-      if (_isolate != null) {
-        await _refreshStack(_isolate.pauseEvent);
+      if (isolate != null) {
+        await _refreshStack(isolate.pauseEvent);
       }
       flushStdio();
       reportStatus();
@@ -1468,9 +1466,7 @@
     // TODO(turnidge): Stop relying on the isolate to track the last
     // pause event.  Since we listen to events directly in the
     // debugger, this could introduce a race.
-    return (isolate != null &&
-            isolate.pauseEvent != null &&
-            isolate.pauseEvent is M.ResumeEvent);
+    return isolate.status == M.IsolateStatus.paused;
   }
 
   void warnOutOfDate() {
@@ -1482,7 +1478,7 @@
     });
   }
 
-  Future<ServiceMap> _refreshStack(M.DebugEvent pauseEvent) {
+  Future<S.ServiceMap> _refreshStack(M.DebugEvent pauseEvent) {
     return isolate.getStack().then((result) {
       if (result.isSentinel) {
         // The isolate has gone away.  The IsolateExit event will
@@ -1502,25 +1498,25 @@
 
   void reportStatus() {
     flushStdio();
-    if (_isolate == null) {
+    if (isolate == null) {
       console.print('No current isolate');
-    } else if (_isolate.idle) {
+    } else if (isolate.idle) {
       console.print('Isolate is idle');
-    } else if (_isolate.running) {
+    } else if (isolate.running) {
       console.print("Isolate is running (type 'pause' to interrupt)");
-    } else if (_isolate.pauseEvent != null) {
-      _reportPause(_isolate.pauseEvent);
+    } else if (isolate.pauseEvent != null) {
+      _reportPause(isolate.pauseEvent);
     } else {
       console.print('Isolate is in unknown state');
     }
     warnOutOfDate();
   }
 
-  void _reportIsolateError(Isolate isolate, M.DebugEvent event) {
+  void _reportIsolateError(S.Isolate isolate, M.DebugEvent event) {
     if (isolate == null) {
       return;
     }
-    DartError error = isolate.error;
+    S.DartError error = isolate.error;
     if (error == null) {
       return;
     }
@@ -1565,7 +1561,7 @@
           "(type 'continue' or [F7] to exit the isolate')");
       _reportIsolateError(isolate, event);
     } else if (stack['frames'].length > 0) {
-      Frame frame = stack['frames'][0];
+      S.Frame frame = stack['frames'][0];
       var script = frame.location.script;
       script.load().then((_) {
         var line = script.tokenToLine(frame.location.tokenPos);
@@ -1582,7 +1578,7 @@
           // This seems to be missing if we are paused-at-exception after
           // paused-at-isolate-exit. Maybe we shutdown part of the debugger too
           // soon?
-          console.printRef(event.exception);
+          console.printRef(isolate, event.exception, instances);
         } else {
           console.print('Paused at ${script.name}:${line}:${col}');
         }
@@ -1593,17 +1589,17 @@
     }
   }
 
-  Future _reportBreakpointEvent(ServiceEvent event) async {
+  Future _reportBreakpointEvent(S.ServiceEvent event) async {
     var bpt = event.breakpoint;
     var verb = null;
     switch (event.kind) {
-      case ServiceEvent.kBreakpointAdded:
+      case S.ServiceEvent.kBreakpointAdded:
         verb = 'added';
         break;
-      case ServiceEvent.kBreakpointResolved:
+      case S.ServiceEvent.kBreakpointResolved:
         verb = 'resolved';
         break;
-      case ServiceEvent.kBreakpointRemoved:
+      case S.ServiceEvent.kBreakpointRemoved:
         verb = 'removed';
         break;
       default:
@@ -1623,26 +1619,22 @@
     }
   }
 
-  void onEvent(ServiceEvent event) {
+  void onEvent(S.ServiceEvent event) {
     switch(event.kind) {
-      case ServiceEvent.kVMUpdate:
+      case S.ServiceEvent.kVMUpdate:
         var vm = event.owner;
         console.print("VM ${vm.target.networkAddress} renamed to '${vm.name}'");
         break;
 
-      case ServiceEvent.kIsolateStart:
+      case S.ServiceEvent.kIsolateStart:
         {
           var iso = event.owner;
           console.print(
               "Isolate ${iso.number} '${iso.name}' has been created");
-          if (isolate == null) {
-            console.print("Switching to isolate ${iso.number} '${iso.name}'");
-            isolate = iso;
-          }
         }
         break;
 
-      case ServiceEvent.kIsolateExit:
+      case S.ServiceEvent.kIsolateExit:
         {
           var iso = event.owner;
           if (iso == isolate) {
@@ -1651,11 +1643,9 @@
             var isolates = vm.isolates;
             if (isolates.length > 0) {
               var newIsolate = isolates.first;
-              console.print("Switching to isolate "
-                            "${newIsolate.number} '${newIsolate.name}'");
-              isolate = newIsolate;
+              new AnchorElement(href: Uris.debugger(newIsolate)).click();
             } else {
-              isolate = null;
+              new AnchorElement(href: Uris.vm()).click();
             }
           } else {
             console.print(
@@ -1664,19 +1654,19 @@
         }
         break;
 
-      case ServiceEvent.kDebuggerSettingsUpdate:
+      case S.ServiceEvent.kDebuggerSettingsUpdate:
         if (breakOnException != event.exceptions) {
           breakOnException = event.exceptions;
           console.print("Now pausing for exceptions: $breakOnException");
         }
         break;
 
-      case ServiceEvent.kIsolateUpdate:
+      case S.ServiceEvent.kIsolateUpdate:
         var iso = event.owner;
         console.print("Isolate ${iso.number} renamed to '${iso.name}'");
         break;
 
-      case ServiceEvent.kIsolateReload:
+      case S.ServiceEvent.kIsolateReload:
         var reloadError = event.reloadError;
         if (reloadError != null) {
           console.print('Isolate reload failed: ${event.reloadError}');
@@ -1685,11 +1675,11 @@
         }
         break;
 
-      case ServiceEvent.kPauseStart:
-      case ServiceEvent.kPauseExit:
-      case ServiceEvent.kPauseBreakpoint:
-      case ServiceEvent.kPauseInterrupted:
-      case ServiceEvent.kPauseException:
+      case S.ServiceEvent.kPauseStart:
+      case S.ServiceEvent.kPauseExit:
+      case S.ServiceEvent.kPauseBreakpoint:
+      case S.ServiceEvent.kPauseInterrupted:
+      case S.ServiceEvent.kPauseException:
         if (event.owner == isolate) {
           var e = createEventFromServiceEvent(event);
           _refreshStack(e).then((_) async {
@@ -1702,29 +1692,29 @@
         }
         break;
 
-      case ServiceEvent.kResume:
+      case S.ServiceEvent.kResume:
         if (event.owner == isolate) {
           flushStdio();
           console.print('Continuing...');
         }
         break;
 
-      case ServiceEvent.kBreakpointAdded:
-      case ServiceEvent.kBreakpointResolved:
-      case ServiceEvent.kBreakpointRemoved:
+      case S.ServiceEvent.kBreakpointAdded:
+      case S.ServiceEvent.kBreakpointResolved:
+      case S.ServiceEvent.kBreakpointRemoved:
         if (event.owner == isolate) {
           _reportBreakpointEvent(event);
         }
         break;
 
-      case ServiceEvent.kIsolateRunnable:
-      case ServiceEvent.kGraph:
-      case ServiceEvent.kGC:
-      case ServiceEvent.kInspect:
+      case S.ServiceEvent.kIsolateRunnable:
+      case S.ServiceEvent.kGraph:
+      case S.ServiceEvent.kGC:
+      case S.ServiceEvent.kInspect:
         // Ignore.
         break;
 
-      case ServiceEvent.kLogging:
+      case S.ServiceEvent.kLogging:
         _consolePrinter.onEvent(event.logRecord['level'].name, event);
         break;
 
@@ -1740,11 +1730,11 @@
     _consolePrinter.flush();
   }
 
-  void onStdout(ServiceEvent event) {
+  void onStdout(S.ServiceEvent event) {
     _consolePrinter.onEvent('stdout', event);
   }
 
-  void onStderr(ServiceEvent event) {
+  void onStderr(S.ServiceEvent event) {
     _consolePrinter.onEvent('stderr', event);
   }
 
@@ -1798,7 +1788,7 @@
     return cmd.runCommand(command).then((_) {
       lastCommand = command;
     }).catchError((e, s) {
-      if (e is NetworkRpcException) {
+      if (e is S.NetworkRpcException) {
         console.printRed('Unable to execute command because the connection '
                       'to the VM has been closed');
       } else {
@@ -1921,20 +1911,42 @@
   }
 }
 
-@CustomTag('debugger-page')
-class DebuggerPageElement extends ObservatoryElement {
-  @published Isolate isolate;
+class DebuggerPageElement  extends HtmlElement implements Renderable {
+  static const tag = const Tag<DebuggerPageElement>('debugger-page',
+                                                    dependencies: const [
+                                                      NavTopMenuElement.tag,
+                                                      NavVMMenuElement.tag,
+                                                      NavIsolateMenuElement.tag,
+                                                      NavNotifyElement.tag,
+                                                    ]);
 
-  isolateChanged(oldValue) {
-    debugger.updateIsolate(isolate);
-  }
-  ObservatoryDebugger debugger = new ObservatoryDebugger();
+  S.Isolate _isolate;
+  ObservatoryDebugger _debugger;
+  M.InstanceRepository _instances;
+  M.ScriptRepository _scripts;
+  M.EventRepository _events;
 
-  DebuggerPageElement.created() : super.created() {
-    debugger.page = this;
+  factory DebuggerPageElement(S.Isolate isolate,
+                              M.InstanceRepository instances,
+                              M.ScriptRepository scripts,
+                              M.EventRepository events) {
+    assert(isolate != null);
+    assert(instances != null);
+    assert(scripts != null);
+    assert(events != null);
+    final e = document.createElement(tag.name);
+    final debugger = new ObservatoryDebugger(isolate);
+    debugger.page = e;
+    e._isolate = isolate;
+    e._debugger = debugger;
+    e._instances = instances;
+    e._scripts = scripts;
+    e._events = events;
+    return e;
   }
 
-  StreamSubscription _resizeSubscription;
+  DebuggerPageElement.created() : super.created();
+
   Future<StreamSubscription> _vmSubscriptionFuture;
   Future<StreamSubscription> _isolateSubscriptionFuture;
   Future<StreamSubscription> _debugSubscriptionFuture;
@@ -1942,30 +1954,65 @@
   Future<StreamSubscription> _stderrSubscriptionFuture;
   Future<StreamSubscription> _logSubscriptionFuture;
 
+  ObservatoryApplication get app => ObservatoryApplication.app;
+
+  Timer _timer;
+
+  static final consoleElement = new DebuggerConsoleElement();
+
   @override
   void attached() {
     super.attached();
-    _onResize(null);
+
+    final stackDiv = new DivElement()..classes = ['stack'];
+    final stackElement = new DebuggerStackElement(_isolate, _debugger, stackDiv,
+                                                  _instances, _scripts,
+                                                  _events);
+    stackDiv.children = [stackElement];
+    final consoleDiv = new DivElement()..classes = ['console']
+      ..children = [consoleElement];
+    final commandElement = new DebuggerInputElement(_isolate, _debugger);
+    final commandDiv = new DivElement()..classes = ['commandline']
+      ..children = [commandElement];
+
+    children = [
+      navBar([
+        new NavTopMenuElement(queue: app.queue),
+        new NavVMMenuElement(app.vm, app.events, queue: app.queue),
+        new NavIsolateMenuElement(_isolate, app.events, queue: app.queue),
+        navMenu('debugger'),
+        new NavNotifyElement(app.notifications, notifyOnPause: false,
+                             queue: app.queue)
+      ]),
+      new DivElement()..classes = ['variable']
+        ..children = [
+          stackDiv,
+          new DivElement()
+            ..children = [
+              new HRElement()..classes = ['splitter']
+            ],
+          consoleDiv,
+        ],
+      commandDiv
+    ];
+
+    DebuggerConsoleElement._scrollToBottom(consoleDiv);
 
     // Wire the debugger object to the stack, console, and command line.
-    var stackElement = $['stackElement'];
-    debugger.stackElement = stackElement;
-    stackElement.debugger = debugger;
-    stackElement.scroller = $['stackDiv'];
-    debugger.console = $['console'];
-    debugger.input = $['commandline'];
-    debugger.input.debugger = debugger;
-    debugger.init();
+    _debugger.stackElement = stackElement;
+    _debugger.console = consoleElement;
+    _debugger.input = commandElement;
+    _debugger.input._debugger = _debugger;
+    _debugger.init();
 
-    _resizeSubscription = window.onResize.listen(_onResize);
     _vmSubscriptionFuture =
-        app.vm.listenEventStream(VM.kVMStream, debugger.onEvent);
+        app.vm.listenEventStream(S.VM.kVMStream, _debugger.onEvent);
     _isolateSubscriptionFuture =
-        app.vm.listenEventStream(VM.kIsolateStream, debugger.onEvent);
+        app.vm.listenEventStream(S.VM.kIsolateStream, _debugger.onEvent);
     _debugSubscriptionFuture =
-        app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent);
+        app.vm.listenEventStream(S.VM.kDebugStream, _debugger.onEvent);
     _stdoutSubscriptionFuture =
-        app.vm.listenEventStream(VM.kStdoutStream, debugger.onStdout);
+        app.vm.listenEventStream(S.VM.kStdoutStream, _debugger.onStdout);
     if (_stdoutSubscriptionFuture != null) {
       // TODO(turnidge): How do we want to handle this in general?
       _stdoutSubscriptionFuture.catchError((e, st) {
@@ -1974,7 +2021,7 @@
       });
     }
     _stderrSubscriptionFuture =
-        app.vm.listenEventStream(VM.kStderrStream, debugger.onStderr);
+        app.vm.listenEventStream(S.VM.kStderrStream, _debugger.onStderr);
     if (_stderrSubscriptionFuture != null) {
       // TODO(turnidge): How do we want to handle this in general?
       _stderrSubscriptionFuture.catchError((e, st) {
@@ -1983,9 +2030,11 @@
       });
     }
     _logSubscriptionFuture =
-        app.vm.listenEventStream(Isolate.kLoggingStream, debugger.onEvent);
+        app.vm.listenEventStream(S.Isolate.kLoggingStream, _debugger.onEvent);
     // Turn on the periodic poll timer for this page.
-    pollPeriod = const Duration(milliseconds:100);
+    _timer = new Timer.periodic(const Duration(milliseconds:100), (_) {
+      _debugger.flushStdio();
+    });
 
     onClick.listen((event) {
       // Random clicks should focus on the text box.  If the user selects
@@ -1993,70 +2042,140 @@
       var selection = window.getSelection();
       if (selection == null ||
           (selection.type != 'Range' && selection.type != 'text')) {
-        debugger.input.focus();
+        _debugger.input.focus();
       }
     });
   }
 
-  void onPoll() {
-    debugger.flushStdio();
-  }
-
-  void _onResize(_) {
-    var navbarDiv = $['navbarDiv'];
-    var stackDiv = $['stackDiv'];
-    var splitterDiv = $['splitterDiv'];
-    var cmdDiv = $['commandDiv'];
-
-    // For now, force navbar height to 40px in the debugger.
-    // TODO (cbernaschina) check if this is needed.
-    const navbarHeight = 40;
-    int splitterHeight = splitterDiv.clientHeight;
-    int cmdHeight = cmdDiv.clientHeight;
-
-    int windowHeight = window.innerHeight;
-    int fixedHeight = navbarHeight + splitterHeight + cmdHeight;
-    int available = windowHeight - fixedHeight;
-    int stackHeight = available ~/ 1.6;
-    navbarDiv.style.setProperty('height', '${navbarHeight}px');
-    stackDiv.style.setProperty('height', '${stackHeight}px');
-  }
-
   @override
   void detached() {
-    debugger.isolate = null;
-    _resizeSubscription.cancel();
-    _resizeSubscription = null;
-    cancelFutureSubscription(_vmSubscriptionFuture);
+    _timer.cancel();
+    children = const [];
+    S.cancelFutureSubscription(_vmSubscriptionFuture);
     _vmSubscriptionFuture = null;
-    cancelFutureSubscription(_isolateSubscriptionFuture);
+    S.cancelFutureSubscription(_isolateSubscriptionFuture);
     _isolateSubscriptionFuture = null;
-    cancelFutureSubscription(_debugSubscriptionFuture);
+    S.cancelFutureSubscription(_debugSubscriptionFuture);
     _debugSubscriptionFuture = null;
-    cancelFutureSubscription(_stdoutSubscriptionFuture);
+    S.cancelFutureSubscription(_stdoutSubscriptionFuture);
     _stdoutSubscriptionFuture = null;
-    cancelFutureSubscription(_stderrSubscriptionFuture);
+    S.cancelFutureSubscription(_stderrSubscriptionFuture);
     _stderrSubscriptionFuture = null;
-    cancelFutureSubscription(_logSubscriptionFuture);
+    S.cancelFutureSubscription(_logSubscriptionFuture);
     _logSubscriptionFuture = null;
     super.detached();
   }
 }
 
-@CustomTag('debugger-stack')
-class DebuggerStackElement extends ObservatoryElement {
-  @published Isolate isolate;
-  @published Element scroller;
-  @observable bool hasStack = false;
-  @observable bool hasMessages = false;
-  @observable bool isSampled = false;
-  @observable int currentFrame;
-  ObservatoryDebugger debugger;
+class DebuggerStackElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<DebuggerStackElement>('debugger-stack');
 
-  _addFrame(List frameList, Frame frameInfo) {
-    DebuggerFrameElement frameElement = new Element.tag('debugger-frame');
-    frameElement.frame = frameInfo;
-    frameElement.scroller = scroller;
+  S.Isolate _isolate;
+  M.InstanceRepository _instances;
+  M.ScriptRepository _scripts;
+  M.EventRepository _events;
+  Element _scroller;
+  DivElement _isSampled;
+  bool get isSampled => !_isSampled.classes.contains('hidden');
+  set isSampled(bool value) {
+    if (value != isSampled) {
+      _isSampled.classes.toggle('hidden');
+    }
+  }
+  DivElement _hasStack;
+  bool get hasStack => _hasStack.classes.contains('hidden');
+  set hasStack(bool value) {
+    if (value != hasStack) {
+      _hasStack.classes.toggle('hidden');
+    }
+  }
+  DivElement _hasMessages;
+  bool get hasMessages => _hasMessages.classes.contains('hidden');
+  set hasMessages(bool value) {
+    if (value != hasMessages) {
+      _hasMessages.classes.toggle('hidden');
+    }
+  }
+  UListElement _frameList;
+  UListElement _messageList;
+  int currentFrame;
+  ObservatoryDebugger _debugger;
+
+  factory DebuggerStackElement(S.Isolate isolate,
+                               ObservatoryDebugger debugger,
+                               Element scroller,
+                               M.InstanceRepository instances,
+                               M.ScriptRepository scripts,
+                               M.EventRepository events) {
+    assert(isolate != null);
+    assert(debugger != null);
+    assert(scroller != null);
+    assert(instances != null);
+    assert(scripts != null);
+    assert(events != null);
+    final e = document.createElement(tag.name);
+    e._isolate = isolate;
+    e._debugger = debugger;
+    e._scroller = scroller;
+    e._instances = instances;
+    e._scripts = scripts;
+    e._events = events;
+
+    var btnPause;
+    var btnRefresh;
+    e.children = [
+      e._isSampled = new DivElement()..classes = ['sampledMessage', 'hidden']
+        ..children = [
+          new SpanElement()
+            ..text = 'The program is not paused. '
+                     'The stack trace below may be out of date.',
+          new BRElement(),
+          new BRElement(),
+          btnPause = new ButtonElement()
+            ..text = '[Pause Isolate]'
+            ..onClick.listen((_) async {
+              btnPause.disabled = true;
+              try {
+                await debugger.isolate.pause();
+              }
+              finally {
+                btnPause.disabled = false;
+              }
+            }),
+          btnRefresh = new ButtonElement()
+            ..text = '[Refresh Stack]'
+            ..onClick.listen((_) async {
+              btnRefresh.disabled = true;
+              try {
+                await debugger.refreshStack();
+              }
+              finally {
+                btnRefresh.disabled = false;
+              }
+            }),
+          new BRElement(),
+          new BRElement(),
+          new HRElement()..classes = ['splitter']
+        ],
+      e._hasStack = new DivElement()..classes = ['noStack', 'hidden']
+        ..text = 'No stack',
+      e._frameList = new UListElement()..classes = ['list-group'],
+      new HRElement(),
+      e._hasMessages = new DivElement()..classes = ['noMessages', 'hidden']
+        ..text = 'No pending messages',
+      e._messageList = new UListElement()..classes = ['messageList']
+    ];
+    return e;
+  }
+
+  _addFrame(List frameList, S.Frame frameInfo) {
+    final frameElement = new DebuggerFrameElement(_isolate,
+                                                  frameInfo,
+                                                  _scroller,
+                                                  _instances,
+                                                  _scripts,
+                                                  _events,
+                                                  queue: app.queue);
 
     if (frameInfo.index == currentFrame) {
       frameElement.setCurrent(true);
@@ -2071,9 +2190,13 @@
     frameList.insert(0, li);
   }
 
-  _addMessage(List messageList, ServiceMessage messageInfo) {
-    DebuggerMessageElement messageElement = new Element.tag('debugger-message');
-    messageElement.message = messageInfo;
+  _addMessage(List messageList, S.ServiceMessage messageInfo) {
+    final messageElement = new DebuggerMessageElement(_isolate,
+                                                      messageInfo,
+                                                      _instances,
+                                                      _scripts,
+                                                      _events,
+                                                      queue: app.queue);
 
     var li = new LIElement();
     li.classes.add('list-group-item');
@@ -2082,8 +2205,10 @@
     messageList.add(li);
   }
 
-  void updateStackFrames(ServiceMap newStack) {
-    List frameElements = $['frameList'].children;
+  ObservatoryApplication get app => ObservatoryApplication.app;
+
+  void updateStackFrames(S.ServiceMap newStack) {
+    List frameElements = _frameList.children;
     List newFrames = newStack['frames'];
 
     // Remove any frames whose functions don't match, starting from
@@ -2132,8 +2257,8 @@
     hasStack = frameElements.isNotEmpty;
   }
 
-  void updateStackMessages(ServiceMap newStack) {
-    List messageElements = $['messageList'].children;
+  void updateStackMessages(S.ServiceMap newStack) {
+    List messageElements = _messageList.children;
     List newMessages = newStack['messages'];
 
     // Remove any extra message elements.
@@ -2157,14 +2282,15 @@
     if (messageElements.isNotEmpty) {
       // Update old messages.
       for (int i = 0; i < newStartingIndex; i++) {
-        messageElements[i].children[0].updateMessage(newMessages[i]);
+        DebuggerMessageElement e = messageElements[i].children[0];
+        e.updateMessage(newMessages[i]);
       }
     }
 
     hasMessages = messageElements.isNotEmpty;
   }
 
-  void updateStack(ServiceMap newStack, M.DebugEvent pauseEvent) {
+  void updateStack(S.ServiceMap newStack, M.DebugEvent pauseEvent) {
     updateStackFrames(newStack);
     updateStackMessages(newStack);
     isSampled = pauseEvent == null;
@@ -2172,9 +2298,9 @@
 
   void setCurrentFrame(int value) {
     currentFrame = value;
-    List frameElements = $['frameList'].children;
+    List frameElements = _frameList.children;
     for (var frameElement in frameElements) {
-      var dbgFrameElement = frameElement.children[0];
+      DebuggerFrameElement dbgFrameElement = frameElement.children[0];
       if (dbgFrameElement.frame.index == currentFrame) {
         dbgFrameElement.setCurrent(true);
       } else {
@@ -2183,29 +2309,24 @@
     }
   }
 
-  Future doPauseIsolate() {
-    if (debugger != null) {
-      return debugger.isolate.pause();
-    } else {
-      return new Future.value(null);
-    }
-  }
-
-  Future doRefreshStack() {
-    if (debugger != null) {
-      return debugger.refreshStack();
-    } else {
-      return new Future.value(null);
-    }
-  }
-
   DebuggerStackElement.created() : super.created();
 }
 
-@CustomTag('debugger-frame')
-class DebuggerFrameElement extends ObservatoryElement {
-  @published Frame frame;
-  @published Element scroller;
+class DebuggerFrameElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<DebuggerFrameElement>('debugger-frame');
+
+  RenderingScheduler<DebuggerMessageElement> _r;
+
+  Stream<RenderedEvent<DebuggerMessageElement>> get onRendered => _r.onRendered;
+
+  Element _scroller;
+  DivElement _varsDiv;
+  M.Isolate _isolate;
+  S.Frame _frame;
+  S.Frame get frame => _frame;
+  M.InstanceRepository _instances;
+  M.ScriptRepository _scripts;
+  M.EventRepository _events;
 
   // Is this the current frame?
   bool _current = false;
@@ -2213,99 +2334,238 @@
   // Has this frame been pinned open?
   bool _pinned = false;
 
+  bool _expanded = false;
+
   void setCurrent(bool value) {
-    busy = true;
-    frame.function.load().then((func) {
+    _frame.function.load().then((func) {
       _current = value;
-      var frameOuter = $['frameOuter'];
       if (_current) {
-        frameOuter.classes.add('current');
         _expand();
         scrollIntoView();
       } else {
-        frameOuter.classes.remove('current');
         if (_pinned) {
           _expand();
         } else {
           _unexpand();
         }
       }
-      busy = false;
     });
   }
 
-  @observable String scriptHeight;
-  @observable bool expanded = false;
-  @observable bool busy = false;
+  factory DebuggerFrameElement(M.Isolate isolate,
+                               S.Frame frame,
+                               Element scroller,
+                               M.InstanceRepository instances,
+                               M.ScriptRepository scripts,
+                               M.EventRepository events,
+                               {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(frame != null);
+    assert(scroller != null);
+    assert(instances != null);
+    assert(scripts != null);
+    assert(events != null);
+    final DebuggerFrameElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._frame = frame;
+    e._scroller = scroller;
+    e._instances = instances;
+    e._scripts = scripts;
+    e._events = events;
+    return e;
+  }
 
   DebuggerFrameElement.created() : super.created();
 
+  void render() {
+    if (_pinned) {
+      classes.add('shadow');
+    } else {
+      classes.remove('shadow');
+    }
+    if (_current) {
+      classes.add('current');
+    } else {
+      classes.remove('current');
+    }
+    ButtonElement expandButton;
+    final content = <Element>[
+      expandButton = new ButtonElement()
+        ..children = _createHeader()
+        ..onClick.listen((e) async {
+          if (e.target is AnchorElement) {
+            return;
+          }
+          expandButton.disabled = true;
+          await _toggleExpand();
+          expandButton.disabled = false;
+        })
+    ];
+    if (_expanded) {
+      final homeMethod = _frame.function.homeMethod;
+      String homeMethodName;
+      if ((homeMethod.dartOwner is S.Class) && homeMethod.isStatic) {
+        homeMethodName = '<class>';
+      } else if (homeMethod.dartOwner is S.Library) {
+        homeMethodName = '<library>';
+      }
+      ButtonElement collapseButton;
+      content.addAll([
+        new DivElement()..classes = ['frameDetails']
+          ..children = [
+            new DivElement()..classes = ['flex-row-wrap']
+              ..children = [
+                new DivElement()..classes = ['flex-item-script']
+                  ..children = _frame.function?.location == null ? const []
+                    : [
+                      new SourceInsetElement(_isolate,
+                          _frame.function.location, _scripts, _instances,
+                          _events, currentPos: _frame.location.tokenPos,
+                          variables: _frame.variables, inDebuggerContext: true,
+                          queue: _r.queue)
+                    ],
+                new DivElement()..classes = ['flex-item-vars']
+                  ..children = [
+                    _varsDiv = new DivElement()
+                      ..classes = ['memberList', 'frameVars']
+                      ..children = ([
+                        new DivElement()..classes = ['memberItem']
+                          ..children = homeMethodName == null ? const []
+                            : [
+                              new DivElement()..classes = ['memberName']
+                                ..text = homeMethodName,
+                              new DivElement()..classes = ['memberName']
+                                ..children = [
+                                  anyRef(_isolate, homeMethod.dartOwner,
+                                         _instances, queue: _r.queue)
+                                ]
+                            ]
+                      ]..addAll(_frame.variables.map((v) =>
+                        new DivElement()..classes = ['memberItem']
+                          ..children = [
+                            new DivElement()..classes = ['memberName']
+                              ..text = v.name,
+                            new DivElement()..classes = ['memberName']
+                              ..children = [
+                                anyRef(_isolate, v['value'], _instances,
+                                       queue: _r.queue)
+                              ]
+                          ]
+                      ).toList()))
+                  ]
+              ],
+            new DivElement()..classes = ['frameContractor']
+              ..children = [
+                collapseButton = new ButtonElement()
+                  ..onClick.listen((e) async {
+                    collapseButton.disabled = true;
+                    await _toggleExpand();
+                    collapseButton.disabled = false;
+                  })
+                  ..children = [
+                    iconExpandLess.clone(true)
+                  ]
+              ]
+          ]
+      ]);
+    }
+    children = content;
+  }
+
+  List<Element> _createHeader() {
+    final content = [
+      new DivElement()..classes = ['frameSummaryText']
+        ..children = [
+          new DivElement()..classes = ['frameId']
+            ..text = 'Frame ${_frame.index}',
+          new SpanElement()
+            ..children = _frame.function == null ? const []
+              : [
+                new FunctionRefElement(_isolate, _frame.function,
+                                       queue: _r.queue)
+              ],
+          new SpanElement()..text = ' ( ',
+          new SpanElement()
+            ..children = _frame.function?.location == null ? const []
+              : [
+                  new SourceLinkElement(_isolate, _frame.function.location,
+                                        _scripts,
+                                        queue: _r.queue)
+              ],
+          new SpanElement()..text = ' )'
+        ]
+    ];
+    if (!_expanded) {
+      content.add(new DivElement()..classes = ['frameExpander']
+        ..children = [
+          iconExpandMore.clone(true)
+        ]);
+    }
+    return [
+      new DivElement()..classes = ['frameSummary']
+        ..children = content
+    ];
+  }
+
   String makeExpandKey(String key) {
-    return '${frame.function.qualifiedName}/${key}';
+    return '${_frame.function.qualifiedName}/${key}';
   }
 
-  bool matchFrame(Frame newFrame) {
-    return newFrame.function.id == frame.function.id;
+  bool matchFrame(S.Frame newFrame) {
+    return newFrame.function.id == _frame.function.id;
   }
 
-  void updateFrame(Frame newFrame) {
+  void updateFrame(S.Frame newFrame) {
     assert(matchFrame(newFrame));
-    frame = newFrame;
+    _frame = newFrame;
   }
 
-  Script get script => frame.location.script;
+  S.Script get script => _frame.location.script;
 
   int _varsTop(varsDiv) {
-    const minTop = 5;
+    const minTop = 0;
     if (varsDiv == null) {
       return minTop;
     }
-    // TODO (cbernaschina) check if this is needed.
-    const navbarHeight = 40;
-    const bottomPad = 6;
-    var parent = varsDiv.parent.getBoundingClientRect();
-    var varsHeight = varsDiv.clientHeight;
-    var maxTop = parent.height - (varsHeight + bottomPad);
-    var adjustedTop = navbarHeight - parent.top;
+    final paddingTop = document.body.contentEdge.top;
+    final parent = varsDiv.parent.getBoundingClientRect();
+    final varsHeight = varsDiv.clientHeight;
+    final maxTop = parent.height - varsHeight;
+    final adjustedTop = paddingTop - parent.top;
     return (max(minTop, min(maxTop, adjustedTop)));
   }
 
   void _onScroll(event) {
-    if (!expanded) {
+    if (!_expanded || _varsDiv == null) {
       return;
     }
-    var varsDiv = shadowRoot.querySelector('#vars');
-    if (varsDiv == null) {
-      return;
-    }
-    var currentTop = varsDiv.style.top;
-    var newTop = _varsTop(varsDiv);
+    var currentTop = _varsDiv.style.top;
+    var newTop = _varsTop(_varsDiv);
     if (currentTop != newTop) {
-      varsDiv.style.top = '${newTop}px';
+      _varsDiv.style.top = '${newTop}px';
     }
   }
 
   void _expand() {
-    var frameOuter = $['frameOuter'];
-    expanded = true;
-    frameOuter.classes.add('shadow');
+    _expanded = true;
     _subscribeToScroll();
+    _r.dirty();
   }
 
   void _unexpand() {
-    var frameOuter = $['frameOuter'];
-    expanded = false;
+    _expanded = false;
     _unsubscribeToScroll();
-    frameOuter.classes.remove('shadow');
+    _r.dirty();
   }
 
   StreamSubscription _scrollSubscription;
   StreamSubscription _resizeSubscription;
 
   void _subscribeToScroll() {
-    if (scroller != null) {
+    if (_scroller != null) {
       if (_scrollSubscription == null) {
-        _scrollSubscription = scroller.onScroll.listen(_onScroll);
+        _scrollSubscription = _scroller.onScroll.listen(_onScroll);
       }
       if (_resizeSubscription == null) {
         _resizeSubscription = window.onResize.listen(_onScroll);
@@ -2327,56 +2587,42 @@
   @override
   void attached() {
     super.attached();
-    int windowHeight = window.innerHeight;
-    scriptHeight = '${windowHeight ~/ 1.6}px';
-    if (expanded) {
+    _r.enable();
+    if (_expanded) {
       _subscribeToScroll();
     }
   }
 
   void detached() {
-    _unsubscribeToScroll();
+    _r.disable(notify: true);
     super.detached();
+    _unsubscribeToScroll();
   }
 
-  void toggleExpand(var a, var b, var c) {
-    if (busy) {
-      return;
+  Future _toggleExpand() async {
+    await _frame.function.load();
+    _pinned = !_pinned;
+    if (_pinned) {
+      _expand();
+    } else {
+      _unexpand();
     }
-    busy = true;
-    frame.function.load().then((func) {
-        _pinned = !_pinned;
-        if (_pinned) {
-          _expand();
-        } else {
-          _unexpand();
-        }
-        busy = false;
-      });
-  }
-
-  @observable
-  get properLocals {
-    var locals = new List();
-    var homeMethod = frame.function.homeMethod;
-    if (homeMethod.dartOwner is Class && homeMethod.isStatic) {
-      locals.add(
-          {'name' : '<class>',
-           'value' : homeMethod.dartOwner});
-    } else if (homeMethod.dartOwner is Library) {
-      locals.add(
-          {'name' : '<library>',
-           'value' : homeMethod.dartOwner});
-    }
-    locals.addAll(frame.variables);
-    return locals;
   }
 }
 
-@CustomTag('debugger-message')
-class DebuggerMessageElement extends ObservatoryElement {
-  @published ServiceMessage message;
-  @observable ServiceObject preview;
+class DebuggerMessageElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<DebuggerMessageElement>('debugger-message');
+
+  RenderingScheduler<DebuggerMessageElement> _r;
+
+  Stream<RenderedEvent<DebuggerMessageElement>> get onRendered => _r.onRendered;
+
+  S.Isolate _isolate;
+  S.ServiceMessage _message;
+  S.ServiceObject _preview;
+  M.InstanceRepository _instances;
+  M.ScriptRepository _scripts;
+  M.EventRepository _events;
 
   // Is this the current message?
   bool _current = false;
@@ -2384,90 +2630,207 @@
   // Has this message been pinned open?
   bool _pinned = false;
 
-  void setCurrent(bool value) {
-    _current = value;
-    var messageOuter = $['messageOuter'];
-    if (_current) {
-      messageOuter.classes.add('current');
-      expanded = true;
-      messageOuter.classes.add('shadow');
-      scrollIntoView();
-    } else {
-      messageOuter.classes.remove('current');
-      if (_pinned) {
-        expanded = true;
-        messageOuter.classes.add('shadow');
-      } else {
-        expanded = false;
-        messageOuter.classes.remove('shadow');
-      }
-    }
-  }
+  bool _expanded = false;
 
-  @observable String scriptHeight;
-  @observable bool expanded = false;
-  @observable bool busy = false;
+  factory DebuggerMessageElement(S.Isolate isolate,
+                                 S.ServiceMessage message,
+                                 M.InstanceRepository instances,
+                                 M.ScriptRepository scripts,
+                                 M.EventRepository events,
+                                 {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(message != null);
+    assert(instances != null);
+    assert(instances != null);
+    assert(events != null);
+    final DebuggerMessageElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._message = message;
+    e._instances = instances;
+    e._scripts = scripts;
+    e._events = events;
+    return e;
+  }
 
   DebuggerMessageElement.created() : super.created();
 
-  void updateMessage(ServiceMessage newMessage) {
-    bool messageChanged =
-        (message.messageObjectId != newMessage.messageObjectId);
-    message = newMessage;
-    if (messageChanged) {
-      // Message object id has changed: clear preview and collapse.
-      preview = null;
-      if (expanded) {
-        toggleExpand(null, null, null);
-      }
+  void render() {
+    if (_pinned) {
+      classes.add('shadow');
+    } else {
+      classes.remove('shadow');
+    }
+    if (_current) {
+      classes.add('current');
+    } else {
+      classes.remove('current');
+    }
+    ButtonElement expandButton;
+    final content = <Element>[
+      expandButton = new ButtonElement()
+        ..children = _createHeader()
+        ..onClick.listen((e) async {
+          if (e.target is AnchorElement) {
+            return;
+          }
+          expandButton.disabled = true;
+          await _toggleExpand();
+          expandButton.disabled = false;
+        })
+    ];
+    if (_expanded) {
+      ButtonElement collapseButton;
+      ButtonElement previewButton;
+      content.addAll([
+        new DivElement()..classes = ['messageDetails']
+          ..children = [
+            new DivElement()..classes = ['flex-row-wrap']
+              ..children = [
+                new DivElement()..classes = ['flex-item-script']
+                  ..children = _message.handler == null ? const []
+                    : [
+                      new SourceInsetElement(_isolate,
+                                             _message.handler.location,
+                                             _scripts,
+                                             _instances,
+                                             _events,
+                                             inDebuggerContext: true,
+                                             queue: _r.queue)
+                    ],
+                new DivElement()..classes = ['flex-item-vars']
+                  ..children = [
+                    new DivElement()..classes = ['memberItem']
+                      ..children = [
+                        new DivElement()..classes = ['memberName'],
+                        new DivElement()..classes = ['memberValue']
+                          ..children = ([
+                            previewButton = new ButtonElement()
+                              ..text = 'preview'
+                              ..onClick.listen((_) {
+                                previewButton.disabled = true;
+
+                              })
+                          ]..addAll(
+                            _preview == null ? const []
+                            : [
+                              anyRef(_isolate, _preview, _instances,
+                                     queue: _r.queue)
+                            ]
+                          ))
+                      ]
+                  ]
+              ],
+            new DivElement()..classes = ['messageContractor']
+              ..children = [
+                collapseButton = new ButtonElement()
+                  ..onClick.listen((e) async {
+                    collapseButton.disabled = true;
+                    await _toggleExpand();
+                    collapseButton.disabled = false;
+                  })
+                  ..children = [
+                    iconExpandLess.clone(true)
+                  ]
+              ]
+          ]
+      ]);
+    }
+    children = content;
+  }
+
+  void updateMessage(S.ServiceMessage message) {
+    assert(_message != null);
+    _message = message;
+    _r.dirty();
+  }
+
+  List<Element> _createHeader() {
+    final content = [
+      new DivElement()..classes = ['messageSummaryText']
+        ..children = [
+          new DivElement()..classes = ['messageId']
+            ..text = 'message ${_message.index}',
+          new SpanElement()
+            ..children = _message.handler == null ? const []
+              : [
+                new FunctionRefElement(_isolate, _message.handler,
+                                       queue: _r.queue)
+              ],
+          new SpanElement()..text = ' ( ',
+          new SpanElement()
+            ..children = _message.location == null ? const []
+              : [
+                  new SourceLinkElement(_isolate, _message.location, _scripts,
+                                 queue: _r.queue)
+              ],
+          new SpanElement()..text = ' )'
+        ]
+    ];
+    if (!_expanded) {
+      content.add(new DivElement()..classes = ['messageExpander']
+        ..children = [
+          iconExpandMore.clone(true)
+        ]);
+    }
+    return [
+      new DivElement()..classes = ['messageSummary']
+        ..children = content
+    ];
+  }
+
+  void setCurrent(bool value) {
+    _current = value;
+    if (_current) {
+      _expanded = true;
+      scrollIntoView();
+      _r.dirty();
+    } else {
+      _expanded = _pinned;
     }
   }
 
   @override
   void attached() {
     super.attached();
-    int windowHeight = window.innerHeight;
-    scriptHeight = '${windowHeight ~/ 1.6}px';
+    _r.enable();
   }
 
-  void toggleExpand(var a, var b, var c) {
-    if (busy) {
-      return;
-    }
-    busy = true;
-    var function = message.handler;
-    var loadedFunction;
-    if (function == null) {
-      // Complete immediately.
-      loadedFunction = new Future.value(null);
-    } else {
-      loadedFunction = function.load();
-    }
-    loadedFunction.then((_) {
-      _pinned = !_pinned;
-      var messageOuter = $['messageOuter'];
-      if (_pinned) {
-        expanded = true;
-        messageOuter.classes.add('shadow');
-      } else {
-        expanded = false;
-        messageOuter.classes.remove('shadow');
-      }
-      busy = false;
-    });
+  @override
+  void detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
   }
 
-  Future<ServiceObject> previewMessage(_) {
-    return message.isolate.getObject(message.messageObjectId).then((result) {
-      preview = result;
+  Future _toggleExpand() async {
+    var function = _message.handler;
+    if (function != null) {
+      await function.load();
+    }
+    _pinned = _pinned;
+    _expanded = true;
+    _r.dirty();
+  }
+
+  Future<S.ServiceObject> previewMessage(_) {
+    return _message.isolate.getObject(_message.messageObjectId).then((result) {
+      _preview = result;
       return result;
     });
   }
 }
 
-@CustomTag('debugger-console')
-class DebuggerConsoleElement extends ObservatoryElement {
-  @published Isolate isolate;
+class DebuggerConsoleElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<DebuggerConsoleElement>('debugger-console');
+
+  factory DebuggerConsoleElement() {
+    final DebuggerConsoleElement e = document.createElement(tag.name);
+    e.children = [
+      new BRElement()
+    ];
+    return e;
+  }
 
   DebuggerConsoleElement.created() : super.created();
 
@@ -2495,9 +2858,8 @@
   }
 
   void _append(HtmlElement span) {
-    var consoleTextElement = $['consoleText'];
     bool autoScroll = _isScrolledToBottom(parent);
-    consoleTextElement.children.add(span);
+    children.add(span);
     if (autoScroll) {
       _scrollToBottom(parent);
     }
@@ -2534,24 +2896,23 @@
   }
 
   void printStdio(List<String> lines) {
-    var consoleTextElement = $['consoleText'];
     bool autoScroll = _isScrolledToBottom(parent);
     for (var line in lines) {
       var span = new SpanElement();
       span.classes.add('green');
       span.appendText(line);
       span.appendText('\n');
-      consoleTextElement.children.add(span);
+      children.add(span);
     }
     if (autoScroll) {
       _scrollToBottom(parent);
     }
   }
 
-  void printRef(Instance ref, { bool newline:true }) {
-    var refElement = new Element.tag('instance-ref');
-    refElement.ref = ref;
-    _append(refElement);
+  void printRef(S.Isolate isolate, S.Instance ref,
+                M.InstanceRepository instances,{ bool newline:true }) {
+    _append(new InstanceRefElement(isolate, ref, instances,
+                                   queue: app.queue));
     if (newline) {
       this.newline();
     }
@@ -2562,20 +2923,168 @@
   }
 
   void clear() {
-    var consoleTextElement = $['consoleText'];
-    consoleTextElement.children.clear();
+    children.clear();
   }
+
+  ObservatoryApplication get app => ObservatoryApplication.app;
 }
 
-@CustomTag('debugger-input')
-class DebuggerInputElement extends ObservatoryElement {
-  @published Isolate isolate;
-  @published String text = '';
-  @observable ObservatoryDebugger debugger;
-  @observable bool busy = false;
-  @observable String modalPrompt = null;
+class DebuggerInputElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<DebuggerInputElement>('debugger-input');
+
+  S.Isolate _isolate;
+  ObservatoryDebugger _debugger;
+  bool _busy = false;
+  final _modalPromptDiv = new DivElement()
+                            ..classes = ['modalPrompt', 'hidden'];
+  final _textBox = new TextInputElement()
+                     ..classes = ['textBox']
+                     ..autofocus = true;
+  String get modalPrompt => _modalPromptDiv.text;
+  set modalPrompt(String value) {
+    if (_modalPromptDiv.text == '') {
+      _modalPromptDiv.classes.remove('hidden');
+    }
+    _modalPromptDiv.text = value;
+    if (_modalPromptDiv.text == '') {
+      _modalPromptDiv.classes.add('hidden');
+    }
+  }
+  String get text => _textBox.value;
+  set text(String value) => _textBox.value = value;
   var modalCallback = null;
 
+  factory DebuggerInputElement(S.Isolate isolate,
+                               ObservatoryDebugger debugger) {
+    final DebuggerInputElement e = document.createElement(tag.name);
+    e.children = [
+      e._modalPromptDiv,
+      e._textBox
+    ];
+    e._textBox.select();
+    e._textBox.onKeyDown.listen(e._onKeyDown);
+    return e;
+  }
+
+  DebuggerInputElement.created() : super.created();
+
+  void _onKeyDown(KeyboardEvent e) {
+    if (_busy) {
+      e.preventDefault();
+      return;
+    }
+    _busy = true;
+    if (modalCallback != null) {
+      if (e.keyCode == KeyCode.ENTER) {
+        var response = text;
+        modalCallback(response).whenComplete(() {
+          text = '';
+          _busy = false;
+        });
+      } else {
+        _busy = false;
+      }
+      return;
+    }
+    switch (e.keyCode) {
+      case KeyCode.TAB:
+        e.preventDefault();
+        int cursorPos = _textBox.selectionStart;
+        _debugger.complete(text.substring(0, cursorPos)).then((completion) {
+          text = completion + text.substring(cursorPos);
+          // TODO(turnidge): Move the cursor to the end of the
+          // completion, rather than the end of the string.
+        }).whenComplete(() {
+          _busy = false;
+        });
+        break;
+
+      case KeyCode.ENTER:
+        var command = text;
+        _debugger.run(command).whenComplete(() {
+          text = '';
+          _busy = false;
+        });
+        break;
+
+      case KeyCode.UP:
+        e.preventDefault();
+        text = _debugger.historyPrev(text);
+        _busy = false;
+        break;
+
+      case KeyCode.DOWN:
+        e.preventDefault();
+        text = _debugger.historyNext(text);
+        _busy = false;
+        break;
+
+      case KeyCode.PAGE_UP:
+        e.preventDefault();
+        try {
+          _debugger.upFrame(1);
+        } on RangeError catch (_) {
+          // Ignore.
+        }
+        _busy = false;
+        break;
+
+      case KeyCode.PAGE_DOWN:
+        e.preventDefault();
+        try {
+          _debugger.downFrame(1);
+        } on RangeError catch (_) {
+          // Ignore.
+        }
+        _busy = false;
+        break;
+
+      case KeyCode.F7:
+        e.preventDefault();
+        _debugger.resume().whenComplete(() {
+          _busy = false;
+        });
+        break;
+
+      case KeyCode.F8:
+        e.preventDefault();
+        _debugger.toggleBreakpoint().whenComplete(() {
+          _busy = false;
+        });
+        break;
+
+      case KeyCode.F9:
+        e.preventDefault();
+        _debugger.smartNext().whenComplete(() {
+          _busy = false;
+        });
+        break;
+
+      case KeyCode.F10:
+        e.preventDefault();
+        _debugger.step().whenComplete(() {
+          _busy = false;
+        });
+        break;
+
+      case KeyCode.SEMICOLON:
+        if (e.ctrlKey) {
+          e.preventDefault();
+          _debugger.console.printRed('^;');
+          _debugger.pause().whenComplete(() {
+            _busy = false;
+          });
+        } else {
+          _busy = false;
+        }
+        break;
+
+      default:
+        _busy = false;
+        break;
+    }
+  }
+
   void enterMode(String prompt, callback) {
     assert(modalPrompt == null);
     modalPrompt = prompt;
@@ -2588,132 +3097,81 @@
     modalCallback = null;
   }
 
-  @override
-  void ready() {
-    super.ready();
-    var textBox = $['textBox'];
-    textBox.select();
-    textBox.onKeyDown.listen((KeyboardEvent e) {
-        if (busy) {
-          e.preventDefault();
-          return;
-        }
-        busy = true;
-        if (modalCallback != null) {
-          if (e.keyCode == KeyCode.ENTER) {
-            var response = text;
-            modalCallback(response).whenComplete(() {
-              text = '';
-              busy = false;
-            });
-          } else {
-            busy = false;
-          }
-          return;
-        }
-        switch (e.keyCode) {
-          case KeyCode.TAB:
-            e.preventDefault();
-            int cursorPos = textBox.selectionStart;
-            debugger.complete(text.substring(0, cursorPos)).then((completion) {
-              text = completion + text.substring(cursorPos);
-              // TODO(turnidge): Move the cursor to the end of the
-              // completion, rather than the end of the string.
-            }).whenComplete(() {
-              busy = false;
-            });
-            break;
-
-          case KeyCode.ENTER:
-            var command = text;
-            debugger.run(command).whenComplete(() {
-              text = '';
-              busy = false;
-            });
-            break;
-
-          case KeyCode.UP:
-            e.preventDefault();
-            text = debugger.historyPrev(text);
-            busy = false;
-            break;
-
-          case KeyCode.DOWN:
-            e.preventDefault();
-            text = debugger.historyNext(text);
-            busy = false;
-            break;
-
-          case KeyCode.PAGE_UP:
-            e.preventDefault();
-            try {
-              debugger.upFrame(1);
-            } on RangeError catch (_) {
-              // Ignore.
-            }
-            busy = false;
-            break;
-
-          case KeyCode.PAGE_DOWN:
-            e.preventDefault();
-            try {
-              debugger.downFrame(1);
-            } on RangeError catch (_) {
-              // Ignore.
-            }
-            busy = false;
-            break;
-
-          case KeyCode.F7:
-            e.preventDefault();
-            debugger.resume().whenComplete(() {
-              busy = false;
-            });
-            break;
-
-          case KeyCode.F8:
-            e.preventDefault();
-            debugger.toggleBreakpoint().whenComplete(() {
-              busy = false;
-            });
-            break;
-
-          case KeyCode.F9:
-            e.preventDefault();
-            debugger.smartNext().whenComplete(() {
-              busy = false;
-            });
-            break;
-
-          case KeyCode.F10:
-            e.preventDefault();
-            debugger.step().whenComplete(() {
-              busy = false;
-            });
-            break;
-
-          case KeyCode.SEMICOLON:
-            if (e.ctrlKey) {
-              e.preventDefault();
-              debugger.console.printRed('^;');
-              debugger.pause().whenComplete(() {
-                busy = false;
-              });
-            } else {
-              busy = false;
-            }
-            break;
-
-          default:
-            busy = false;
-            break;
-        }
-      });
-  }
-
   void focus() {
-    $['textBox'].focus();
+    _textBox.focus();
   }
-
-  DebuggerInputElement.created() : super.created();
 }
+
+final SvgSvgElement iconExpandLess = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PolygonElement()
+        ..setAttribute('points', '12,8 6,14 7.4,15.4 12,10.8 16.6,15.4 18,14 ')
+    ];
+
+final SvgSvgElement iconExpandMore = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PolygonElement()
+        ..setAttribute('points', '16.6,8.6 12,13.2 7.4,8.6 6,10 12,16 18,10 ')
+    ];
+
+final SvgSvgElement iconChevronRight = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PathElement()
+        ..setAttribute('d', 'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z')
+    ];
+
+final SvgSvgElement iconChevronLeft = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PathElement()
+        ..setAttribute('d', 'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z')
+    ];
+
+final SvgSvgElement iconHorizontalThreeDot = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PathElement()
+        ..setAttribute('d', 'M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
+                            '2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
+                            '2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
+                            '2-2-.9-2-2-2z')
+    ];
+
+final SvgSvgElement iconVerticalThreeDot = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PathElement()
+        ..setAttribute('d', 'M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 '
+                            '2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 '
+                            '2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 '
+                            '2-.9 2-2-.9-2-2-2z')
+    ];
+
+final SvgSvgElement iconInfo = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PathElement()
+        ..setAttribute('d', 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 '
+                            '10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z')
+    ];
+
+final SvgSvgElement iconInfoOutline = new SvgSvgElement()
+    ..setAttribute('width', '24')
+    ..setAttribute('height', '24')
+    ..children = [
+      new PathElement()
+        ..setAttribute('d', 'M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 '
+                            '10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 '
+                            '0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 '
+                            '9h2V7h-2v2z')
+    ];
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
deleted file mode 100644
index da96388..0000000
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ /dev/null
@@ -1,478 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="eval_link.html">
-
-<!-- TODO(turnidge): Use core-icon once core_elements work properly in
-     devtools -->
-<polymer-element name="icon-expand-less" noscript>
-  <template>
-    <svg width="24" height="24">
-      <polygon points="12,8 6,14 7.4,15.4 12,10.8 16.6,15.4 18,14 "/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-expand-more" noscript>
-  <template>
-    <svg width="24" height="24">
-      <polygon points="16.6,8.6 12,13.2 7.4,8.6 6,10 12,16 18,10 "/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-chevron-right" noscript>
-  <template>
-    <svg width="24" height="24">
-      <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-chevron-left" noscript>
-  <template>
-    <svg width="24" height="24">
-      <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-horizontal-three-dot" noscript>
-  <template>
-    <svg width="24" height="24">
-      <path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-vertical-three-dot" noscript>
-  <template>
-    <svg width="24" height="24">
-      <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-info" noscript>
-  <template>
-    <svg width="24" height="24">
-      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="icon-info-outline" noscript>
-  <template>
-    <svg width="24" height="24">
-      <path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"/>
-    </svg>
-  </template>
-</polymer-element>
-
-<polymer-element name="debugger-page">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .container {
-        height: 100%;
-        display: flex;
-        flex-direction: column;
-        justify-content: space-between;
-      }
-      nav-bar {
-        flex: 0 0 auto;
-      }
-      .stack {
-        flex: 0 0 auto;
-        overflow-y: auto;
-      }
-      .splitter {
-        height: 0px;
-        margin: 0px;
-        font-size: 1px;
-        border-bottom: 1px solid #888;
-      }
-      core-splitter {
-        flex: 0 0 auto;
-      }
-      .console {
-        flex: 1 1 auto;
-        overflow-x: auto;
-        overflow-y: auto;
-      }
-      .commandline {
-        flex: 0 0 auto;
-      }
-    </style>
-
-    <div class="container">
-      <nav-bar id="navbarDiv" >
-        <top-nav-menu></top-nav-menu>
-	<vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
-        <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
-        <nav-menu link="{{ makeLink('/debugger', isolate) }}" anchor="debugger" last="{{ true }}"></nav-menu>
-        <nav-notify notifications="{{ app.notifications }}"
-                                      notifyOnPause="{{ false }}"></nav-notify>
-      </nav-bar>
-      <div id="stackDiv" class="stack">
-        <debugger-stack id="stackElement" isolate="{{ isolate }}"></debugger-stack>
-      </div>
-      <!--
-      <core-splitter direction="up" allowOverflow=true></core-splitter>
-      -->
-      <div id="splitterDiv"><hr class="splitter"></div>
-      <div id="consoleDiv" class="console">
-        <debugger-console id="console" isolate="{{ isolate }}"></debugger-console>
-      </div>
-      <div id="commandDiv" class="commandline">
-        <debugger-input id="commandline" isolate="{{ isolate }}"></debugger-input>
-      </div>
-    </div>
-  </template>
-</polymer-element>
-
-<polymer-element name="debugger-stack">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .sampledMessage {
-        margin: 0px 20px 10px 20px;
-        font: 400 14px 'Montserrat', sans-serif;
-        line-height: 125%;
-      }
-      .splitter {
-        height: 0px;
-        margin: 0px;
-        font-size: 1px;
-        border-bottom: 1px dashed #888;
-      }
-      .noMessages, .noStack {
-        margin: 10px 0px 10px 25px;
-        font: bold 14px 'Montserrat', sans-serif;
-        line-height: 125%;
-      }
-    </style>
-    <template if="{{ isSampled }}">
-      <div class="sampledMessage">
-        The program is not paused.  The stack trace below may be out of date.<br>
-        <br>
-        <action-link label="Pause Isolate" callback="{{ doPauseIsolate }}">
-        </action-link>
-        <action-link label="Refresh Stack" callback="{{ doRefreshStack }}">
-        </action-link>
-        <br>
-        <br>
-        <hr class="splitter">
-      </div>
-    </template>
-    <template if="{{ !hasStack }}">
-      <div class="noStack">No stack</div>
-    </template>
-    <ul id="frameList" class="list-group">
-      <!-- debugger-frame elements are added programmatically -->
-    </ul>
-    <hr>
-    <template if="{{ !hasMessages }}">
-      <div class="noMessages">No pending messages</div>
-    </template>
-    <ul id="messageList" class="list-group">
-      <!-- debugger-message elements are added programmatically -->
-    </ul>
-  </template>
-</polymer-element>
-
-
-<polymer-element name="debugger-frame">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .frameOuter {
-        position: relative;
-        padding: 5px;
-        border: 1px solid white;
-      }
-      .frameOuter:hover {
-        border: 1px solid #e0e0e0;
-      }
-      .shadow {
-        box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.16),
-                     0 2px 5px 0 rgba(0, 0, 0, 0.26);
-      }
-      .current {
-        box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.26),
-                     0 2px 5px 0 rgba(0, 0, 0, 0.46);
-        border: 1px solid #444;
-      }
-      .frameSummaryText {
-        display: inline-block;
-        padding: 5px;
-      }
-      .frameId {
-        display: inline-block;
-        width: 60px;
-      }
-      .frameOuter .frameExpander {
-        position: absolute;
-        right: 5px;
-        top: 5px;
-        display: none;
-      }
-      .frameOuter:hover .frameExpander{
-        display: inline-block;
-      }
-      .frameContractor {
-        position: absolute;
-        right: 5px;
-        bottom: 5px;
-        display: inline-block;
-      }
-      .flex-item-script {
-        flex-grow: 1;
-        flex-shrink: 1;
-        flex-basis: 765px;
-      }
-      .flex-item-vars {
-        flex-grow: 5;
-        flex-shrink: 0;
-        flex-basis: 250px;
-        overflow-x: hidden;
-      }
-      #vars {
-        position: relative;
-        top: 5px;
-        padding-left:2em;
-        padding-bottom: 5px;
-      }
-    </style>
-    <div id="frameOuter" class="frameOuter">
-      <a on-click="{{ toggleExpand }}">
-        <div class="frameSummary">
-          <div class="frameSummaryText">
-            <div class="frameId"><b>frame {{ frame.index }}</b></div>
-            <function-ref ref="{{ frame.function }}"></function-ref>
-            ( <source-link location="{{ frame.location }}"></source-link> )
-          </div>
-          <template if="{{ !expanded }}">
-            <div class="frameExpander">
-              <icon-expand-more></icon-expand-more>
-            </div>
-          </template>
-        </div>
-      </a>
-
-      <template if="{{expanded}}">
-        <div class="frameDetails">
-          <div class="flex-row-wrap">
-            <div class="flex-item-script">
-              <source-inset height="{{ scriptHeight }}"
-                            location="{{ frame.function.location }}"
-                            currentPos="{{ frame.location.tokenPos }}"
-                            inDebuggerContext="{{ true }}"
-                            scroller="{{ scroller }}"
-                            variables="{{ frame.variables }}">
-              </source-inset>
-            </div>
-            <div class="flex-item-vars">
-              <div id="vars" class="memberList">
-                <template repeat="{{ v in properLocals }}">
-                  {{ v['name']}}&nbsp;:&nbsp;
-                  <any-service-ref ref="{{ v['value'] }}"
-                                   expandKey="{{ makeExpandKey(v['name']) }}"
-                                   asValue="{{ true }}">
-                  </any-service-ref><br>
-                </template>
-              </div>
-            </div>
-          </div>
-          <!-- TODO(turnidge): Add eval box here? -->
-          <div class="frameContractor">
-            <template if="{{expanded}}">
-              <a on-click="{{ toggleExpand }}">
-                <icon-expand-less></icon-expand-less>
-              </a>
-            </template>
-          </div>
-        </div>
-      </template>
-    </div>
-  </template>
-</polymer-element>
-
-<polymer-element name="debugger-message">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .messageOuter {
-        position: relative;
-        padding: 5px;
-        border: 1px solid white;
-      }
-      .messageOuter:hover {
-        border: 1px solid #e0e0e0;
-      }
-      .shadow {
-        box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.16),
-        0 2px 5px 0 rgba(0, 0, 0, 0.26);
-      }
-      .current {
-        box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.26),
-        0 2px 5px 0 rgba(0, 0, 0, 0.46);
-        border: 1px solid #444;
-      }
-      .messageSummaryText {
-        display: inline-block;
-        padding: 5px;
-      }
-      .messageId {
-        display: inline-block;
-        width: 100px;
-      }
-      .messageOuter .messageExpander {
-        position: absolute;
-        right: 5px;
-        top: 5px;
-        display: none;
-      }
-      .messageOuter:hover .messageExpander {
-        display: inline-block;
-      }
-      .messageContractor {
-        position: absolute;
-        right: 5px;
-        bottom: 5px;
-        display: inline-block;
-      }
-      .flex-item-script {
-        flex-grow: 1;
-        flex-shrink: 1;
-        flex-basis: 765px;
-      }
-      .flex-item-vars {
-        flex-grow: 5;
-        flex-shrink: 0;
-        flex-basis: 225px;
-      }
-    </style>
-    <div id="messageOuter" class="messageOuter">
-      <a on-click="{{ toggleExpand }}">
-        <div class="messageSummary">
-          <div class="messageSummaryText">
-            <div class="messageId"><b>message {{ message.index }}</b></div>
-            <function-ref ref="{{ message.handler }}"></function-ref>
-            ( <source-link location="{{ message.location }}">
-            </source-link> )
-          </div>
-          <template if="{{ !expanded }}">
-            <div class="messageExpander">
-              <icon-expand-more></icon-expand-more>
-            </div>
-          </template>
-        </div>
-      </a>
-
-      <template if="{{expanded}}">
-        <div class="messageDetails">
-          <div class="flex-row-wrap">
-            <div class="flex-item-script">
-              <template if="{{ message.handler != null }}">
-              <source-inset height="{{ scriptHeight }}"
-                            location="{{ message.handler.location }}"
-                            inDebuggerContext="{{ true }}">
-              </source-inset>
-              </template>
-            </div>
-            <div class="flex-item-vars">
-              <div class="memberItem">
-                <div class="memberName"></div>
-                <div class="memberValue">
-                  <eval-link callback="{{ previewMessage }}" label="[preview]" result="{{ preview }}"></eval-link>
-                </div>
-              </div>
-            </div>
-          </div>
-          <div class="messageContractor">
-            <template if="{{expanded}}">
-              <a on-click="{{ toggleExpand }}">
-                <icon-expand-less></icon-expand-less>
-              </a>
-            </template>
-          </div>
-        </div>
-      </template>
-    </div>
-  </template>
-</polymer-element>
-
-<polymer-element name="debugger-console">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .console {
-        margin: 0px 20px 10px 20px;
-      }
-      .normal {
-        font: normal 14px consolas, courier, monospace;
-        white-space: pre;
-        line-height: 125%;
-      }
-      .bold {
-        font: bold 14px consolas, courier, monospace;
-        white-space: pre;
-        line-height: 125%;
-      }
-      .red {
-        font: normal 14px consolas, courier, monospace;
-        white-space: pre;
-        line-height: 125%;
-        color: red;
-      }
-      .green {
-        font: normal 14px consolas, courier, monospace;
-        white-space: pre;
-        line-height: 125%;
-        color: green;
-      }
-      .spacer {
-        height: 20px;
-      }
-    </style>
-    <div id="consoleText" class="console">
-      <!-- Console output is added programmatically -->
-    </div>
-  </template>
-</polymer-element>
-
-<polymer-element name="debugger-input">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .container {
-        height: 100%;
-        display: flex;
-        flex-direction: row;
-        justify-content: space-between;
-      }
-      .textBox {
-        flex: 1 1 auto;
-        margin: 20px;
-        padding: 5px;
-        font: 400 16px consolas, courier, monospace;
-        width: 95%;
-      }
-      .modalPrompt {
-        flex: 0 0 auto;
-        margin-top: 20px;
-        margin-left: 20px;
-        padding: 5px;
-        font: 400 16px consolas, courier, monospace;
-        color: red;
-      }
-    </style>
-    <div class="container">
-      <template if="{{ modalPrompt != null }}">
-        <div class="modalPrompt">{{ modalPrompt }}</div>
-      </template>
-      <input id="textBox" class="textBox" type="text" value="{{ text }}" autofocus>
-    </div>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="debugger.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/error_ref.dart b/runtime/observatory/lib/src/elements/error_ref.dart
index 55685ed..8a523d3 100644
--- a/runtime/observatory/lib/src/elements/error_ref.dart
+++ b/runtime/observatory/lib/src/elements/error_ref.dart
@@ -12,14 +12,14 @@
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 
 class ErrorRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<ErrorRefElement>('error-ref-wrapped');
+  static const tag = const Tag<ErrorRefElement>('error-ref');
 
   RenderingScheduler<ErrorRefElement> _r;
 
   Stream<RenderedEvent<ErrorRefElement>> get onRendered => _r.onRendered;
 
   ErrorRef _error;
-  
+
   ErrorRef get error => _error;
 
   factory ErrorRefElement(ErrorRef error, {RenderingQueue queue}) {
diff --git a/runtime/observatory/lib/src/elements/error_ref_wrapper.dart b/runtime/observatory/lib/src/elements/error_ref_wrapper.dart
deleted file mode 100644
index 4b0e7e4..0000000
--- a/runtime/observatory/lib/src/elements/error_ref_wrapper.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/src/elements/error_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-class ErrorRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<ErrorRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<ErrorRefElementWrapper>('error-ref');
-
-  DartError _error;
-
-  DartError get ref => _error;
-
-  void set ref(DartError value) {
-    _error = value;
-    render();
-  }
-
-  ErrorRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_error == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        error-ref-wrapped > pre {
-          background-color: #f5f5f5;
-          border: 1px solid #ccc;
-          padding-left: 10px;
-          padding-right: 10px;
-          font-family: consolas, courier, monospace;
-          font-size: 1em;
-          line-height: 1.2em;
-          white-space: pre;
-        }
-        ''',
-      new ErrorRefElement(_error, queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/error_view.dart b/runtime/observatory/lib/src/elements/error_view.dart
index aeb3aa8..92fee08 100644
--- a/runtime/observatory/lib/src/elements/error_view.dart
+++ b/runtime/observatory/lib/src/elements/error_view.dart
@@ -7,17 +7,16 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/view_footer.dart';
 
 class ErrorViewElement extends HtmlElement implements Renderable{
   static const tag = const Tag<ErrorViewElement>('error-view',
-                     dependencies: const [NavBarElement.tag,
-                                          NavTopMenuElement.tag,
+                     dependencies: const [NavTopMenuElement.tag,
                                           NavNotifyElement.tag,
                                           ViewFooterElement.tag]);
 
@@ -60,11 +59,10 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(last: true, queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()
         ..classes = ['content-centered']
         ..children = [
diff --git a/runtime/observatory/lib/src/elements/eval_box.dart b/runtime/observatory/lib/src/elements/eval_box.dart
index 29f71f0..855cd7a 100644
--- a/runtime/observatory/lib/src/elements/eval_box.dart
+++ b/runtime/observatory/lib/src/elements/eval_box.dart
@@ -13,7 +13,7 @@
 import 'package:observatory/src/elements/instance_ref.dart';
 
 class EvalBoxElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<EvalBoxElement>('eval-box-wrapped',
+  static const tag = const Tag<EvalBoxElement>('eval-box',
                                                 dependencies: const [
                                                   InstanceRefElement.tag
                                                 ]);
diff --git a/runtime/observatory/lib/src/elements/eval_box_wrapper.dart b/runtime/observatory/lib/src/elements/eval_box_wrapper.dart
deleted file mode 100644
index ce6b919..0000000
--- a/runtime/observatory/lib/src/elements/eval_box_wrapper.dart
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/service_html.dart' show HeapObject;
-import 'package:observatory/src/elements/eval_box.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class EvalBoxElementWrapper extends HtmlElement {
-  static const binder = const Binder<EvalBoxElementWrapper>(const {
-      'context': #context
-    });
-
-  static const tag = const Tag<EvalBoxElementWrapper>('eval-box');
-
-  HeapObject _context;
-
-  HeapObject get context => _context;
-
-  void set context(HeapObject value) {
-    _context = value;
-    render();
-  }
-
-  EvalBoxElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_context == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        eval-box-wrapped a[href]:hover {
-            text-decoration: underline;
-        }
-        eval-box-wrapped a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }
-        eval-box-wrapped .quicks > button:hover {
-          background-color: transparent;
-          border: none;
-          text-decoration: underline;
-        }
-        eval-box-wrapped .quicks > button {
-          background-color: transparent;
-          border: none;
-          color: #0489c3;
-          padding: 0;
-          margin-right: 1em;
-          text-decoration: none;
-        }
-        eval-box-wrapped .emphasize {
-          font-style: italic;
-        }
-        eval-box-wrapped .indent {
-          margin-left: 1.5em;
-          font: 400 14px 'Montserrat', sans-serif;
-          line-height: 150%;
-        }
-        eval-box-wrapped .stackTraceBox {
-          margin-left: 1.5em;
-          background-color: #f5f5f5;
-          border: 1px solid #ccc;
-          padding: 10px;
-          font-family: consolas, courier, monospace;
-          font-size: 12px;
-          white-space: pre;
-          overflow-x: auto;
-        }
-        eval-box-wrapped .heading {
-          line-height: 30px;
-          position: relative;
-          box-sizing: border-box;
-          width: 100%;
-          min-width: 450px;
-          padding-right: 150px;
-        }
-        eval-box-wrapped .heading .textbox {
-          width: 100%;
-          min-width: 300px;
-        }
-        eval-box-wrapped .heading .buttons {
-          position: absolute;
-          top: 0;
-          right: 0px;
-        }
-        eval-box-wrapped.historyExpr,
-        eval-box-wrapped .historyValue {
-          vertical-align: text-top;
-          font: 400 14px 'Montserrat', sans-serif;
-        }
-        eval-box-wrapped .historyExpr button {
-          display: block;
-          color: black;
-          border: none;
-          background: none;
-          text-decoration: none;
-          padding: 6px 6px;
-          cursor: pointer;
-          white-space: pre-line;
-        }
-        eval-box-wrapped .historyExpr button:hover {
-          background-color: #fff3e3;
-        }
-        eval-box-wrapped .historyValue {
-          display: block;
-          padding: 6px 6px;
-        }
-        eval-box-wrapped .historyDelete button {
-          border: none;
-          background: none;
-        }
-        eval-box-wrapped .historyDelete button:hover {
-          color: #BB3311;
-        }
-        ''',
-      new EvalBoxElement(_context.isolate, _context,
-                          new InstanceRepository(),
-                          new EvalRepository(),
-                          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/eval_link.dart b/runtime/observatory/lib/src/elements/eval_link.dart
deleted file mode 100644
index aa8be4e..0000000
--- a/runtime/observatory/lib/src/elements/eval_link.dart
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library eval_link_element;
-
-import 'package:observatory/service.dart';
-import 'observatory_element.dart';
-import 'package:polymer/polymer.dart';
-
-@CustomTag('eval-link')
-class EvalLinkElement extends ObservatoryElement {
-  EvalLinkElement.created() : super.created();
-
-  @observable bool busy = false;
-  @published String label = "[evaluate]";
-  @published var callback = null;
-  @published var expr = '';
-  @published var result = null;
-  @published var error = null;
-
-  void evalNow(var a, var b, var c) {
-    if (busy) {
-      return;
-    }
-    if (callback != null) {
-      busy = true;
-      result = null;
-      callback(expr).then((ServiceObject obj) {
-        result = obj;
-      }).catchError((e, st) {
-        error = e.message;
-        app.handleException(e, st);
-      }).whenComplete(() {
-        busy = false;
-      });
-    }
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/eval_link.html b/runtime/observatory/lib/src/elements/eval_link.html
deleted file mode 100644
index d90370e..0000000
--- a/runtime/observatory/lib/src/elements/eval_link.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="eval-link">
-  <template>
-    <style>
-      .idle {
-        color: #0489c3;
-        cursor: pointer;
-      }
-      .busy {
-        color: #aaa;
-        cursor: wait;
-      }
-    </style>
-
-    <template if="{{ busy }}">
-      <span class="busy">{{ label }}</span>
-    </template>
-    <template if="{{ !busy }}">
-      <span class="idle"><a on-click="{{ evalNow }}">{{ label }}</a></span>
-    </template>
-    <template if="{{ error != null }}">
-      = <span style="color:red">{{ error }}</span>
-    </template>
-    <template if="{{ error == null }}">
-      <template if="{{ result != null }}">
-        = <any-service-ref ref="{{ result }}"></any-service-ref>
-      </template>
-    </template>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="eval_link.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/field_ref.dart b/runtime/observatory/lib/src/elements/field_ref.dart
index f86c0f2..960cbae 100644
--- a/runtime/observatory/lib/src/elements/field_ref.dart
+++ b/runtime/observatory/lib/src/elements/field_ref.dart
@@ -11,7 +11,7 @@
 import 'package:observatory/src/elements/instance_ref.dart';
 
 class FieldRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<FieldRefElement>('field-ref-wrapped',
+  static const tag = const Tag<FieldRefElement>('field-ref',
                                                 dependencies: const [
                                                   InstanceRefElement.tag
                                                 ]);
diff --git a/runtime/observatory/lib/src/elements/field_ref_wrapper.dart b/runtime/observatory/lib/src/elements/field_ref_wrapper.dart
deleted file mode 100644
index 35aa76e..0000000
--- a/runtime/observatory/lib/src/elements/field_ref_wrapper.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/service_html.dart' show Field;
-import 'package:observatory/src/elements/field_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class FieldRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<FieldRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<FieldRefElementWrapper>('field-ref');
-
-  Field _field;
-  Field get ref => _field;
-  void set ref(Field ref) {
-    _field = ref;
-    render();
-  }
-
-  FieldRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) return;
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        field-ref-wrapped a[href]:hover {
-            text-decoration: underline;
-        }
-        field-ref-wrapped a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new FieldRefElement(_field.isolate, _field,
-                          new InstanceRepository(),
-                          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/field_view.dart b/runtime/observatory/lib/src/elements/field_view.dart
index 9fe7b82..536dc5d 100644
--- a/runtime/observatory/lib/src/elements/field_view.dart
+++ b/runtime/observatory/lib/src/elements/field_view.dart
@@ -10,13 +10,13 @@
 import 'package:observatory/src/elements/class_ref.dart';
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import 'package:observatory/src/elements/nav/library_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -31,13 +31,11 @@
                                             dependencies: const [
                                               ClassRefElement.tag,
                                               CurlyBlockElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavLibraryMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -153,8 +151,7 @@
       header += _field.declaredType.name;
     }
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = _createMenu(),
+      navBar(_createMenu()),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = '$header ${field.name}',
@@ -195,7 +192,7 @@
       );
     }
     menu.addAll([
-      new NavMenuElement(_field.name, last: true, queue: _r.queue),
+      navMenu(_field.name),
       new NavRefreshElement(queue: _r.queue)
           ..onRefresh.listen((e) {
             e.element.disabled = true;
diff --git a/runtime/observatory/lib/src/elements/flag_list.dart b/runtime/observatory/lib/src/elements/flag_list.dart
index e207251..5405008 100644
--- a/runtime/observatory/lib/src/elements/flag_list.dart
+++ b/runtime/observatory/lib/src/elements/flag_list.dart
@@ -7,11 +7,10 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -20,9 +19,7 @@
 
 class FlagListElement extends HtmlElement implements Renderable {
   static const tag = const Tag<FlagListElement>('flag-list',
-                     dependencies: const [NavBarElement.tag,
-                                          NavMenuElement.tag,
-                                          NavNotifyElement.tag,
+                     dependencies: const [NavNotifyElement.tag,
                                           NavRefreshElement.tag,
                                           NavTopMenuElement.tag,
                                           NavVMMenuElement.tag,
@@ -100,23 +97,21 @@
     }
 
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavMenuElement('flags', link: Uris.flags(), last: true,
-                             queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-            ..onRefresh.listen((e) async {
-              e.element.disabled = true;
-              try {
-                await _refresh();
-              } finally {
-                e.element.disabled = false;
-              }
-            }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        navMenu('flags'),
+        new NavRefreshElement(queue: _r.queue)
+          ..onRefresh.listen((e) async {
+            e.element.disabled = true;
+            try {
+              await _refresh();
+            } finally {
+              e.element.disabled = false;
+            }
+          }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()
         ..classes = ['content-centered']
         ..children = content,
diff --git a/runtime/observatory/lib/src/elements/function_ref.dart b/runtime/observatory/lib/src/elements/function_ref.dart
index 2f18c91..9b2aebd 100644
--- a/runtime/observatory/lib/src/elements/function_ref.dart
+++ b/runtime/observatory/lib/src/elements/function_ref.dart
@@ -15,7 +15,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class FunctionRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<FunctionRefElement>('function-ref-wrapped');
+  static const tag = const Tag<FunctionRefElement>('function-ref');
 
   RenderingScheduler<FunctionRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/function_ref_wrapper.dart b/runtime/observatory/lib/src/elements/function_ref_wrapper.dart
deleted file mode 100644
index dbde827..0000000
--- a/runtime/observatory/lib/src/elements/function_ref_wrapper.dart
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart' show ServiceFunction;
-import 'package:observatory/src/elements/function_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class FunctionRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<FunctionRefElementWrapper>(const {
-      'ref': #ref, 'qualified': #qualified
-    });
-
-  static const tag = const Tag<FunctionRefElementWrapper>('function-ref');
-
-  bool _qualified = true;
-  ServiceFunction _function;
-
-  bool get qualified => _qualified;
-  ServiceFunction get ref => _function;
-
-  void set qualified(bool value) {
-    _qualified = value;
-    render();
-  }
-  void set ref(ServiceFunction value) {
-    _function = value;
-    render();
-  }
-
-  FunctionRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        class-ref-wrapped > a[href]:hover,
-        function-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        class-ref-wrapped > a[href],
-        function-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new FunctionRefElement(_function.isolate, _function, qualified: qualified,
-        queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/function_view.dart b/runtime/observatory/lib/src/elements/function_view.dart
index bc90b3c..a0f3111 100644
--- a/runtime/observatory/lib/src/elements/function_view.dart
+++ b/runtime/observatory/lib/src/elements/function_view.dart
@@ -13,13 +13,13 @@
 import 'package:observatory/src/elements/field_ref.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import 'package:observatory/src/elements/nav/library_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -37,13 +37,11 @@
                                               CurlyBlockElement.tag,
                                               FieldRefElement.tag,
                                               InstanceRefElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavLibraryMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -141,8 +139,7 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = _createMenu(),
+      navBar(_createMenu()),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Function ${_function.name}',
@@ -180,7 +177,7 @@
       );
     }
     menu.addAll([
-      new NavMenuElement(_function.name, last: true, queue: _r.queue),
+      navMenu(_function.name),
       new NavRefreshElement(queue: _r.queue)
           ..onRefresh.listen((e) {
             e.element.disabled = true;
diff --git a/runtime/observatory/lib/src/elements/general_error.dart b/runtime/observatory/lib/src/elements/general_error.dart
index 943ba3c..473e724 100644
--- a/runtime/observatory/lib/src/elements/general_error.dart
+++ b/runtime/observatory/lib/src/elements/general_error.dart
@@ -7,16 +7,15 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 
 class GeneralErrorElement extends HtmlElement implements Renderable {
   static const tag = const Tag<GeneralErrorElement>('general-error',
-                     dependencies: const [NavBarElement.tag,
-                                          NavTopMenuElement.tag,
+                     dependencies: const [NavTopMenuElement.tag,
                                           NavNotifyElement.tag]);
 
   RenderingScheduler _r;
@@ -59,11 +58,10 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(last: true, queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered']
         ..children = [
           new HeadingElement.h1()..text = 'Error',
diff --git a/runtime/observatory/lib/src/elements/heap_map.dart b/runtime/observatory/lib/src/elements/heap_map.dart
index bc361c7..85b97c8 100644
--- a/runtime/observatory/lib/src/elements/heap_map.dart
+++ b/runtime/observatory/lib/src/elements/heap_map.dart
@@ -10,11 +10,11 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/service.dart' as S;
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -22,11 +22,9 @@
 class HeapMapElement  extends HtmlElement implements Renderable {
   static const tag = const Tag<HeapMapElement>('heap-map',
                                             dependencies: const [
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                             ]);
@@ -103,17 +101,15 @@
                   ..onMouseDown.listen(_handleClick);
     }
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('heap map', last: true,
-              link: Uris.heapMap(_isolate), queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-            ..onRefresh.listen((_) => _refresh()),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('heap map'),
+        new NavRefreshElement(queue: _r.queue)
+          ..onRefresh.listen((_) => _refresh()),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = _status,
@@ -230,7 +226,7 @@
     _updateClassList(
         _fragmentation['classList'], _fragmentation['freeClassId']);
     var pages = _fragmentation['pages'];
-    var width = _canvas.parent.client.width;
+    var width = max(_canvas.parent.client.width, 1);
     _pageHeight = _PAGE_SEPARATION_HEIGHT +
         _fragmentation['pageSizeBytes'] ~/
         _fragmentation['unitSizeBytes'] ~/ width;
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart
index c488a65..51c451e 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -13,12 +13,11 @@
 import 'package:observatory/src/elements/class_ref.dart';
 import 'package:observatory/src/elements/containers/virtual_tree.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -34,11 +33,9 @@
   static const tag = const Tag<HeapSnapshotElement>('heap-snapshot',
                                           dependencies: const [
                                             ClassRefElement.tag,
-                                            NavBarElement.tag,
                                             NavTopMenuElement.tag,
                                             NavVMMenuElement.tag,
                                             NavIsolateMenuElement.tag,
-                                            NavMenuElement.tag,
                                             NavRefreshElement.tag,
                                             NavNotifyElement.tag,
                                             VirtualTreeElement.tag,
@@ -106,20 +103,18 @@
 
   void render() {
     final content = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('heap snapshot', link: Uris.heapSnapshot(_isolate),
-              last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..disabled = M.isHeapSnapshotProgressRunning(_progress?.status)
-              ..onRefresh.listen((e) {
-                _refresh();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('heap snapshot'),
+        new NavRefreshElement(queue: _r.queue)
+            ..disabled = M.isHeapSnapshotProgressRunning(_progress?.status)
+            ..onRefresh.listen((e) {
+              _refresh();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
     ];
     if (_progress == null) {
       children = content;
diff --git a/runtime/observatory/lib/src/elements/helpers/any_ref.dart b/runtime/observatory/lib/src/elements/helpers/any_ref.dart
index d70733b..704e1a5 100644
--- a/runtime/observatory/lib/src/elements/helpers/any_ref.dart
+++ b/runtime/observatory/lib/src/elements/helpers/any_ref.dart
@@ -57,8 +57,6 @@
       return new ObjectPoolRefElement(isolate, ref, queue: queue);
     } else if (ref is M.PcDescriptorsRef) {
       return new PcDescriptorsRefElement(isolate, ref, queue: queue);
-    } else if (ref is M.Sentinel) {
-      return new SentinelValueElement(ref, queue: queue);
     } else if (ref is M.ScriptRef) {
       return new ScriptRefElement(isolate, ref, queue: queue);
     } else if (ref is M.TypeArgumentsRef) {
@@ -71,6 +69,8 @@
       return new AnchorElement(href: Uris.inspect(isolate, object: ref))
         ..text = 'object';
     }
+  } else if (ref is M.Sentinel) {
+    return new SentinelValueElement(ref, queue: queue);
   }
   throw new Exception('Unknown runtimeType (${ref.runtimeType})');
 }
diff --git a/runtime/observatory/lib/src/elements/helpers/nav_bar.dart b/runtime/observatory/lib/src/elements/helpers/nav_bar.dart
new file mode 100644
index 0000000..5c1c272
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/helpers/nav_bar.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+Element navBar(Iterable<Element> content) {
+  assert(content != null);
+  return document.createElement('nav')
+    ..classes = ['nav-bar']
+    ..children = [
+      new UListElement()
+        ..children = content,
+    ];
+}
diff --git a/runtime/observatory/lib/src/elements/helpers/nav_menu.dart b/runtime/observatory/lib/src/elements/helpers/nav_menu.dart
new file mode 100644
index 0000000..1e8940e
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/helpers/nav_menu.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+navMenu(String label, {String link: '', Iterable<Element> content: const []}) {
+  assert(label != null);
+  assert(content != null);
+  assert(link != null);
+  return new LIElement()..classes = ['nav-menu']
+    ..children = [
+      new SpanElement()..classes = ['nav-menu_label']
+        ..children = [
+          new AnchorElement(href: link)
+            ..text = label,
+          new UListElement()
+            ..children = content
+        ]
+    ];
+}
diff --git a/runtime/observatory/lib/src/elements/icdata_view.dart b/runtime/observatory/lib/src/elements/icdata_view.dart
index bd66760..1582a27 100644
--- a/runtime/observatory/lib/src/elements/icdata_view.dart
+++ b/runtime/observatory/lib/src/elements/icdata_view.dart
@@ -7,11 +7,11 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -23,11 +23,9 @@
   static const tag = const Tag<ICDataViewElement>('icdata-view',
                                             dependencies: const [
                                               CurlyBlockElement.tag,
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -110,21 +108,19 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('instance', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _icdata = await _icdatas.get(_isolate, _icdata.id);
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
-
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('icdata'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _icdata = await _icdatas.get(_isolate, _icdata.id);
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'ICData',
diff --git a/runtime/observatory/lib/src/elements/inbound_references.dart b/runtime/observatory/lib/src/elements/inbound_references.dart
index f186507..f8d69f3 100644
--- a/runtime/observatory/lib/src/elements/inbound_references.dart
+++ b/runtime/observatory/lib/src/elements/inbound_references.dart
@@ -67,7 +67,7 @@
   void render() {
     children = [
       new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
-        ..children = _createContent()
+        ..content = _createContent()
         ..onToggle.listen((e) async {
           _expanded = e.control.expanded;
           if (_expanded) {
diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart
index d0f2874..f54b41b 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref.dart
@@ -15,7 +15,7 @@
 import 'package:observatory/utils.dart';
 
 class InstanceRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<InstanceRefElement>('instance-ref-wrapped');
+  static const tag = const Tag<InstanceRefElement>('instance-ref');
 
   RenderingScheduler<InstanceRefElement> _r;
 
@@ -65,7 +65,7 @@
       content.addAll([
         new SpanElement()..text = ' ',
         new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
-          ..children = [
+          ..content = [
             new DivElement()..classes = ['indent']
               ..children = _createValue()
           ]
@@ -154,7 +154,7 @@
           new AnchorElement(href: Uris.inspect(_isolate, object: _instance))
             ..text = _instance.clazz.name,
           new CurlyBlockElement(queue: _r.queue)
-            ..children = [
+            ..content = [
               new DivElement()..classes = ['stackTraceBox']
                 ..text = _instance.valueAsString
             ]
diff --git a/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart b/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart
deleted file mode 100644
index 2ebff79..0000000
--- a/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/service_html.dart' show Instance;
-import 'package:observatory/src/elements/instance_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class InstanceRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<InstanceRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<InstanceRefElementWrapper>('instance-ref');
-
-  Instance _instance;
-  Instance get ref => _instance;
-  void set ref(Instance ref) {
-    _instance = ref;
-    render();
-  }
-
-  InstanceRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) return;
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        instance-ref-wrapped a[href]:hover {
-            text-decoration: underline;
-        }
-        instance-ref-wrapped a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }
-        instance-ref-wrapped .emphasize {
-          font-style: italic;
-        }
-        instance-ref-wrapped .indent {
-          margin-left: 1.5em;
-          font: 400 14px 'Montserrat', sans-serif;
-          line-height: 150%;
-        }
-        instance-ref-wrapped .stackTraceBox {
-          margin-left: 1.5em;
-          background-color: #f5f5f5;
-          border: 1px solid #ccc;
-          padding: 10px;
-          font-family: consolas, courier, monospace;
-          font-size: 12px;
-          white-space: pre;
-          overflow-x: auto;
-        }''',
-      new InstanceRefElement(_instance.isolate, _instance,
-                             new InstanceRepository(),
-                             queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/instance_view.dart b/runtime/observatory/lib/src/elements/instance_view.dart
index 675adaf..6f40929 100644
--- a/runtime/observatory/lib/src/elements/instance_view.dart
+++ b/runtime/observatory/lib/src/elements/instance_view.dart
@@ -14,14 +14,14 @@
 import 'package:observatory/src/elements/field_ref.dart';
 import 'package:observatory/src/elements/function_ref.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import 'package:observatory/src/elements/nav/library_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -41,13 +41,11 @@
                                               FieldRefElement.tag,
                                               FunctionRefElement.tag,
                                               InstanceRefElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavLibraryMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -185,8 +183,7 @@
       new ViewFooterElement(queue: _r.queue)
     ]);
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = _createMenu(),
+      navBar(_createMenu()),
       new DivElement()..classes = ['content-centered-big']
         ..children = content
       ];
@@ -204,7 +201,7 @@
     }
     menu.addAll([
       new NavClassMenuElement(_isolate, _instance.clazz, queue: _r.queue),
-      new NavMenuElement('instance', last: true, queue: _r.queue),
+      navMenu('instance'),
       new NavRefreshElement(queue: _r.queue)
           ..onRefresh.listen((e) {
             e.element.disabled = true;
@@ -361,7 +358,7 @@
               new CurlyBlockElement(
                   expanded: _instance.nativeFields.length <= 100,
                   queue: _r.queue)
-                ..children = [
+                ..content = [
                    new DivElement()..classes = ['memberList']
                     ..children = _instance.nativeFields.map((f) =>
                       new DivElement()..classes = ['memberItem']
@@ -387,7 +384,7 @@
               new CurlyBlockElement(
                   expanded: fields.length <= 100,
                   queue: _r.queue)
-                ..children = [
+                ..content = [
                   new DivElement()..classes = ['memberList']
                     ..children = fields.map((f) =>
                       new DivElement()..classes = ['memberItem']
@@ -459,7 +456,7 @@
               new CurlyBlockElement(
                   expanded: associations.length <= 100,
                   queue: _r.queue)
-                ..children = [
+                ..content = [
                   new DivElement()..classes = ['memberList']
                     ..children = associations.map((a) =>
                       new DivElement()..classes = ['memberItem']
@@ -504,7 +501,7 @@
               new CurlyBlockElement(
                   expanded: typedElements.length <= 100,
                   queue: _r.queue)
-                ..children = [
+                ..content = [
                   new DivElement()..classes = ['memberList']
                     ..children = typedElements.map((e) =>
                       new DivElement()..classes = ['memberItem']
diff --git a/runtime/observatory/lib/src/elements/isolate_reconnect.dart b/runtime/observatory/lib/src/elements/isolate_reconnect.dart
index 465bc0c..df3e77a 100644
--- a/runtime/observatory/lib/src/elements/isolate_reconnect.dart
+++ b/runtime/observatory/lib/src/elements/isolate_reconnect.dart
@@ -7,18 +7,17 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/view_footer.dart';
 
 class IsolateReconnectElement extends HtmlElement implements Renderable{
   static const tag = const Tag<IsolateReconnectElement>('isolate-reconnect',
-                     dependencies: const [NavBarElement.tag,
-                                          NavTopMenuElement.tag,
+                     dependencies: const [NavTopMenuElement.tag,
                                           NavNotifyElement.tag,
                                           ViewFooterElement.tag]);
 
@@ -78,11 +77,10 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(last: true, queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()
         ..classes = ['content-centered']
         ..children = [
diff --git a/runtime/observatory/lib/src/elements/isolate_ref.dart b/runtime/observatory/lib/src/elements/isolate_ref.dart
index 4440001..2bee70b 100644
--- a/runtime/observatory/lib/src/elements/isolate_ref.dart
+++ b/runtime/observatory/lib/src/elements/isolate_ref.dart
@@ -13,7 +13,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class IsolateRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<IsolateRefElement>('isolate-ref-wrapped');
+  static const tag = const Tag<IsolateRefElement>('isolate-ref');
 
   RenderingScheduler<IsolateRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart b/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
deleted file mode 100644
index 6c9547b..0000000
--- a/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service_html.dart' show Isolate;
-import 'package:observatory/src/elements/isolate_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class IsolateRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<IsolateRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<IsolateRefElementWrapper>('isolate-ref');
-
-  Isolate _isolate;
-
-  Isolate get ref => _isolate;
-
-  void set ref(Isolate value) {
-    _isolate = value;
-    render();
-  }
-
-  IsolateRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        isolate-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        isolate-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new IsolateRefElement(_isolate, app.events, queue: app.queue)
-    ];
-  }
-
-  ObservatoryApplication get app => ObservatoryApplication.app;
-}
diff --git a/runtime/observatory/lib/src/elements/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index 88a15d5..55d9332 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -10,6 +10,7 @@
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/eval_box.dart';
 import 'package:observatory/src/elements/function_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
@@ -17,7 +18,6 @@
 import 'package:observatory/src/elements/isolate/run_state.dart';
 import 'package:observatory/src/elements/isolate/shared_summary.dart';
 import 'package:observatory/src/elements/library_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
@@ -38,7 +38,6 @@
                                               IsolateRunStateElement.tag,
                                               IsolateSharedSummaryElement.tag,
                                               LibraryRefElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavIsolateMenuElement.tag,
@@ -133,27 +132,26 @@
     final uptime = new DateTime.now().difference(_isolate.startTime);
     final libraries = _isolate.libraries.toList();
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, last: true,
-                                    queue: _r.queue),
-          new NavRefreshElement(label: 'reload source', queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                await _isolates.reloadSources(_isolate);
-                _r.dirty();
-              }),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _isolate = await _isolates.get(_isolate);
-                await _loadExtraData();
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events,
+                                  queue: _r.queue),
+        new NavRefreshElement(label: 'reload source', queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              await _isolates.reloadSources(_isolate);
+              _r.dirty();
+            }),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _isolate = await _isolates.get(_isolate);
+              await _loadExtraData();
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Isolate ${_isolate.name}',
@@ -257,7 +255,7 @@
                   new DivElement()..classes = ['memberValue']
                     ..children = [
                       new CurlyBlockElement(queue: _r.queue)
-                        ..children = libraries.map((l) =>
+                        ..content = libraries.map((l) =>
                           new DivElement()
                             ..children = [
                               new LibraryRefElement(_isolate, l,
diff --git a/runtime/observatory/lib/src/elements/json_view.dart b/runtime/observatory/lib/src/elements/json_view.dart
index 93eeeda..8134064 100644
--- a/runtime/observatory/lib/src/elements/json_view.dart
+++ b/runtime/observatory/lib/src/elements/json_view.dart
@@ -7,9 +7,9 @@
 import 'dart:async';
 import 'dart:html';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/view_footer.dart';
@@ -17,7 +17,6 @@
 class JSONViewElement extends HtmlElement implements Renderable {
   static const tag = const Tag<JSONViewElement>('json-view',
                                                 dependencies: const [
-                                                  NavBarElement.tag,
                                                   NavTopMenuElement.tag,
                                                   NavNotifyElement.tag,
                                                   ViewFooterElement.tag
@@ -63,11 +62,10 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Object',
diff --git a/runtime/observatory/lib/src/elements/library_ref.dart b/runtime/observatory/lib/src/elements/library_ref.dart
index be8918b..f749828 100644
--- a/runtime/observatory/lib/src/elements/library_ref.dart
+++ b/runtime/observatory/lib/src/elements/library_ref.dart
@@ -13,7 +13,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class LibraryRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<LibraryRefElement>('library-ref-wrapped');
+  static const tag = const Tag<LibraryRefElement>('library-ref');
 
   RenderingScheduler<LibraryRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/library_ref_as_value.dart b/runtime/observatory/lib/src/elements/library_ref_as_value.dart
deleted file mode 100644
index 6de3313..0000000
--- a/runtime/observatory/lib/src/elements/library_ref_as_value.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library library_ref_as_value_element;
-
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
-import 'dart:async';
-
-@CustomTag('library-ref-as-value')
-class LibraryRefAsValueElement extends ServiceRefElement {
-  LibraryRefAsValueElement.created() : super.created();
-
-  String makeExpandKey(String key) {
-    return '${expandKey}/${key}';
-  }
-
-  dynamic expander() {
-    return expandEvent;
-  }
-
-  void expandEvent(bool expand, Function onDone) {
-    if (expand) {
-      Library lib = ref;
-      lib.reload().then((result) {
-        return Future.wait(lib.variables.map((field) => field.reload()));
-      }).whenComplete(onDone);
-    } else {
-      onDone();
-    }
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/library_ref_as_value.html b/runtime/observatory/lib/src/elements/library_ref_as_value.html
deleted file mode 100644
index 49dc900..0000000
--- a/runtime/observatory/lib/src/elements/library_ref_as_value.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="library-ref-as-value">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      .indented {
-      margin-left: 1.5em;
-      font: 400 14px 'Montserrat', sans-serif;
-      line-height: 150%;
-      }
-    </style>
-    <library-ref ref="{{ ref }}"></library-ref>
-    <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
-      <div class="indented">
-        <template repeat="{{ field in ref.variables }}">
-          <template if="{{ field.isStatic }}">
-            {{ field.name }}&nbsp;:&nbsp;
-            <any-service-ref ref="{{ field.staticValue }}"
-                             expandKey="{{ makeExpandKey(field.name) }}">
-            </any-service-ref><br>
-          </template>
-        </template>
-      </div>
-    </curly-block>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="library_ref_as_value.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/library_ref_wrapper.dart b/runtime/observatory/lib/src/elements/library_ref_wrapper.dart
deleted file mode 100644
index 0a2caf4..0000000
--- a/runtime/observatory/lib/src/elements/library_ref_wrapper.dart
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service_html.dart' show Library;
-import 'package:observatory/src/elements/library_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class LibraryRefElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<LibraryRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<LibraryRefElementWrapper>('library-ref');
-
-  Library _library;
-  Library get ref => _library;
-  void set ref(Library ref) { _library = ref; render(); }
-
-  LibraryRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (ref == null) return;
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        library-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        library-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new LibraryRefElement(_library.isolate, _library,
-          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/library_view.dart b/runtime/observatory/lib/src/elements/library_view.dart
index 1c2b374..052e6f4 100644
--- a/runtime/observatory/lib/src/elements/library_view.dart
+++ b/runtime/observatory/lib/src/elements/library_view.dart
@@ -13,12 +13,12 @@
 import 'package:observatory/src/elements/field_ref.dart';
 import 'package:observatory/src/elements/function_ref.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/library_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/library_menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -37,11 +37,10 @@
                                                      FieldRefElement.tag,
                                                      FunctionRefElement.tag,
                                                      LibraryRefElement.tag,
-                                                     NavBarElement.tag,
                                                      NavTopMenuElement.tag,
                                                      NavVMMenuElement.tag,
                                                      NavIsolateMenuElement.tag,
-                                                     NavMenuElement.tag,
+                                                     NavLibraryMenuElement.tag,
                                                      NavRefreshElement.tag,
                                                      NavNotifyElement.tag,
                                                      ObjectCommonElement.tag,
@@ -140,20 +139,18 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('instance', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _refresh();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
-
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        new NavLibraryMenuElement(_isolate, _library, queue: _r.queue),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _refresh();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'ICData',
@@ -218,7 +215,7 @@
       ..children = [
         new SpanElement()..text = 'dependencies (${dependencies.length}) ',
         new CurlyBlockElement(queue: _r.queue)
-          ..children = dependencies.map((d) =>
+          ..content = dependencies.map((d) =>
             new DivElement()..classes = ['indent']
               ..children = [
                 new SpanElement()..text = d.isImport ? 'import ' : 'export ',
@@ -239,7 +236,7 @@
       ..children = [
         new SpanElement()..text = 'scripts (${scripts.length}) ',
         new CurlyBlockElement(queue: _r.queue)
-          ..children = scripts.map((s) =>
+          ..content = scripts.map((s) =>
             new DivElement()..classes = ['indent']
               ..children = [
                 new ScriptRefElement(_isolate, s, queue: _r.queue)
@@ -256,7 +253,7 @@
       ..children = [
         new SpanElement()..text = 'classes (${classes.length}) ',
         new CurlyBlockElement(queue: _r.queue)
-          ..children = classes.map((c) =>
+          ..content = classes.map((c) =>
             new DivElement()..classes = ['indent']
               ..children = [
                 new ClassRefElement(_isolate, c, queue: _r.queue)
@@ -273,7 +270,7 @@
       ..children = [
         new SpanElement()..text = 'variables (${variables.length}) ',
         new CurlyBlockElement(queue: _r.queue)
-          ..children = [
+          ..content = [
             _variables == null
               ? (new SpanElement()..text = 'loading...')
               : (new DivElement()..classes = ['indent', 'memberList']
@@ -305,7 +302,7 @@
       ..children = [
         new SpanElement()..text = 'functions (${functions.length}) ',
         new CurlyBlockElement(queue: _r.queue)
-          ..children = functions.map((f) =>
+          ..content = functions.map((f) =>
             new DivElement()..classes = ['indent']
               ..children = [
                 new FunctionRefElement(_isolate, f, queue: _r.queue)
diff --git a/runtime/observatory/lib/src/elements/logging.dart b/runtime/observatory/lib/src/elements/logging.dart
index e519a0a..67ac79d 100644
--- a/runtime/observatory/lib/src/elements/logging.dart
+++ b/runtime/observatory/lib/src/elements/logging.dart
@@ -8,13 +8,13 @@
 import 'dart:html';
 import 'package:logging/logging.dart';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/logging_list.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/class_menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -25,12 +25,10 @@
   static const tag = const Tag<LoggingPageElement>('logging-page',
                                             dependencies: const [
                                               LoggingListElement.tag,
-                                              NavBarElement.tag,
                                               NavClassMenuElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ViewFooterElement.tag
@@ -89,20 +87,19 @@
     _logs = _logs ?? new LoggingListElement(_isolate, _events);
     _logs.level = _level;
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('logging', last: true, queue: _r.queue),
-          new NavRefreshElement(label: 'clear', queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _logs = null;
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('logging'),
+        new NavRefreshElement(label: 'clear', queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _logs = null;
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Logging',
diff --git a/runtime/observatory/lib/src/elements/logging_list.dart b/runtime/observatory/lib/src/elements/logging_list.dart
index b1dcb55..e803639 100644
--- a/runtime/observatory/lib/src/elements/logging_list.dart
+++ b/runtime/observatory/lib/src/elements/logging_list.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.
 
-library logging_page;
-
 import 'dart:async';
 import 'dart:html';
 import 'package:logging/logging.dart';
diff --git a/runtime/observatory/lib/src/elements/megamorphiccache_ref.dart b/runtime/observatory/lib/src/elements/megamorphiccache_ref.dart
index 7d63976..e596727 100644
--- a/runtime/observatory/lib/src/elements/megamorphiccache_ref.dart
+++ b/runtime/observatory/lib/src/elements/megamorphiccache_ref.dart
@@ -12,7 +12,7 @@
 
 class MegamorphicCacheRefElement extends HtmlElement implements Renderable {
   static const tag =
-      const Tag<MegamorphicCacheRefElement>('megamorphic-cache-ref-wrapped');
+      const Tag<MegamorphicCacheRefElement>('megamorphic-cache-ref');
 
   RenderingScheduler<MegamorphicCacheRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/megamorphiccache_view.dart b/runtime/observatory/lib/src/elements/megamorphiccache_view.dart
index d14e7c7..541b472 100644
--- a/runtime/observatory/lib/src/elements/megamorphiccache_view.dart
+++ b/runtime/observatory/lib/src/elements/megamorphiccache_view.dart
@@ -10,11 +10,11 @@
 import 'package:observatory/src/elements/context_ref.dart';
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -28,11 +28,9 @@
                                                 dependencies: const [
                                                   ContextRefElement.tag,
                                                   CurlyBlockElement.tag,
-                                                  NavBarElement.tag,
                                                   NavTopMenuElement.tag,
                                                   NavVMMenuElement.tag,
                                                   NavIsolateMenuElement.tag,
-                                                  NavMenuElement.tag,
                                                   NavRefreshElement.tag,
                                                   NavNotifyElement.tag,
                                                   ObjectCommonElement.tag,
@@ -117,20 +115,19 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('object', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _cache = await _caches.get(_isolate, _cache.id);
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('megamorphic inline cache'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _cache = await _caches.get(_isolate, _cache.id);
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Megamorphic Cache',
diff --git a/runtime/observatory/lib/src/elements/metric/details.dart b/runtime/observatory/lib/src/elements/metric/details.dart
new file mode 100644
index 0000000..28e7686
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/metric/details.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+
+class MetricDetailsElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<MetricDetailsElement>('metric-details');
+
+  RenderingScheduler<MetricDetailsElement> _r;
+
+  Stream<RenderedEvent<MetricDetailsElement>> get onRendered => _r.onRendered;
+
+  M.IsolateRef _isolate;
+  M.Metric _metric;
+  M.MetricRepository _metrics;
+
+  M.IsolateRef get isolate => _isolate;
+  M.Metric get metric => _metric;
+
+  factory MetricDetailsElement(M.IsolateRef isolate, M.Metric metric,
+                               M.MetricRepository metrics,
+                               {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(metric != null);
+    assert(metrics != null);
+    MetricDetailsElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._metric = metric;
+    e._metrics = metrics;
+    return e;
+  }
+
+  MetricDetailsElement.created() : super.created();
+
+  @override
+  void attached() {
+    super.attached();
+    _r.enable();
+  }
+
+  @override
+  void detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
+  }
+
+  void render() {
+    children = [
+      new DivElement()..classes = ['memberList']
+        ..children = [
+          new DivElement()..classes = ['memberItem']
+            ..children = [
+              new DivElement()..classes = ['memberName']
+                ..text = 'name',
+              new DivElement()..classes = ['memberValue']
+                ..text = _metric.name,
+            ],
+          new DivElement()..classes = ['memberItem']
+            ..children = [
+              new DivElement()..classes = ['memberName']
+                ..text = 'description',
+              new DivElement()..classes = ['memberValue']
+                ..text = _metric.description,
+            ],
+          new DivElement()..classes = ['memberItem']
+            ..children = [
+              new DivElement()..classes = ['memberName']
+                ..text = 'refresh rate',
+              new DivElement()..classes = ['memberValue']
+                ..children = _createRefreshRateSelect(),
+            ],
+          new DivElement()..classes = ['memberItem']
+            ..children = [
+              new DivElement()..classes = ['memberName']
+                ..text = 'buffer size',
+              new DivElement()..classes = ['memberValue']
+                ..children = _createBufferSizeSelect(),
+            ]
+        ]
+    ];
+  }
+
+  List<Element> _createRefreshRateSelect() {
+    final current = _metrics.getSamplingRate(_isolate, _metric);
+    var s;
+    return [
+      s = new SelectElement()
+        ..value = _rateToString(current)
+        ..children = M.MetricSamplingRate.values.map((rate) {
+            return new OptionElement(value: _rateToString(current),
+                selected: current == rate)
+              ..text = _rateToString(rate);
+          }).toList(growable: false)
+        ..onChange.listen((_) {
+            _metrics.setSamplingRate(_isolate, _metric,
+                M.MetricSamplingRate.values[s.selectedIndex]);
+            _r.dirty();
+          })
+    ];
+  }
+
+  List<Element> _createBufferSizeSelect() {
+    final current = _metrics.getBufferSize(_isolate, _metric);
+    var s;
+    return [
+      s = new SelectElement()
+        ..value = _sizeToString(current)
+        ..children = M.MetricBufferSize.values.map((rate) {
+            return new OptionElement(value: _sizeToString(current),
+                selected: current == rate)
+              ..text = _sizeToString(rate);
+          }).toList(growable: false)
+        ..onChange.listen((_) {
+            _metrics.setBufferSize(_isolate, _metric,
+                M.MetricBufferSize.values[s.selectedIndex]);
+            _r.dirty();
+          })
+    ];
+  }
+
+  static String _rateToString(M.MetricSamplingRate rate) {
+    switch (rate) {
+      case M.MetricSamplingRate.off: return 'Never';
+      case M.MetricSamplingRate.e100ms: return 'Ten times per second';
+      case M.MetricSamplingRate.e1s: return 'Once a second';
+      case M.MetricSamplingRate.e2s: return 'Every two seconds';
+      case M.MetricSamplingRate.e4s: return 'Every four seconds';
+      case M.MetricSamplingRate.e8s: return 'Every eight seconds';
+    }
+    throw new Exception('Unknown MetricSamplingRate ($rate)');
+  }
+
+  static String _sizeToString(M.MetricBufferSize size) {
+    switch (size) {
+      case M.MetricBufferSize.n10samples: return '10';
+      case M.MetricBufferSize.n100samples: return '100';
+      case M.MetricBufferSize.n1000samples: return '1000';
+    }
+    throw new Exception('Unknown MetricSamplingRate ($size)');
+  }
+}
diff --git a/runtime/observatory/lib/src/elements/metric/graph.dart b/runtime/observatory/lib/src/elements/metric/graph.dart
new file mode 100644
index 0000000..cc0d370
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/metric/graph.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:charted/charted.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+
+class MetricGraphElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<MetricGraphElement>('metric-graph');
+
+  RenderingScheduler<MetricGraphElement> _r;
+
+  Stream<RenderedEvent<MetricGraphElement>> get onRendered => _r.onRendered;
+
+  M.IsolateRef _isolate;
+  M.Metric _metric;
+  M.MetricRepository _metrics;
+  Timer _timer;
+
+  M.IsolateRef get isolate => _isolate;
+  M.Metric get metric => _metric;
+
+  factory MetricGraphElement(M.IsolateRef isolate, M.Metric metric,
+                               M.MetricRepository metrics,
+                               {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(metric != null);
+    assert(metrics != null);
+    MetricGraphElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._metric = metric;
+    e._metrics = metrics;
+    return e;
+  }
+
+  MetricGraphElement.created() : super.created();
+
+  @override
+  void attached() {
+    super.attached();
+    _r.enable();
+    _timer = new Timer.periodic(const Duration(seconds: 1), (_) => _r.dirty());
+  }
+
+  @override
+  void detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
+    _timer.cancel();
+  }
+
+  final _columns = [
+      new ChartColumnSpec(label: 'Time', type: ChartColumnSpec.TYPE_TIMESTAMP),
+      new ChartColumnSpec(label: 'Value', formatter: (v) => v.toString())
+  ];
+
+  void render() {
+    final min = _metrics.getMinValue(_isolate, _metric);
+    final max = _metrics.getMaxValue(_isolate, _metric);
+    final rows = _metrics.getSamples(_isolate, _metric).map((s) =>
+      [s.time.millisecondsSinceEpoch, s.value]).toList();
+    final current = rows.last.last;
+
+    var message = 'current: $current';
+    if (min != null) {
+      message = 'min: $min, ' + message;
+    }
+    if (max != null) {
+      message = message + ', max: $max';
+    }
+
+    final host = new DivElement();
+    children = [
+      new DivElement()..classes = ['memberList']
+        ..children = [
+          new DivElement()..classes = ['memberItem']
+            ..children = min == null ? const [] : [
+              new DivElement()..classes = ['memberName']
+                ..text = 'min',
+              new DivElement()..classes = ['memberValue']
+                ..text = '$min'
+            ],
+          new DivElement()..classes = ['memberItem']
+            ..children = [
+              new DivElement()..classes = ['memberName']
+                ..text = 'current',
+              new DivElement()..classes = ['memberValue']
+                ..text = '$current'
+            ],
+          new DivElement()..classes = ['memberItem']
+            ..children = max == null ? const [] : [
+              new DivElement()..classes = ['memberName']
+                ..text = 'max',
+              new DivElement()..classes = ['memberValue']
+                ..text = '$max'
+            ]
+        ],
+      new DivElement()..classes = ['graph']
+        ..children = [
+          host
+        ]
+    ];
+    if (rows.length <= 1) {
+      return;
+    }
+    final rect = host.getBoundingClientRect();
+    var series = new ChartSeries("one", [1], new LineChartRenderer());
+    var config = new ChartConfig([series], [0]);
+    config.minimumSize = new Rect(rect.width, rect.height);
+    final data = new ChartData(_columns, rows);
+    new CartesianArea(host, data, config, state: new ChartState()).draw();
+  }
+}
diff --git a/runtime/observatory/lib/src/elements/metrics.dart b/runtime/observatory/lib/src/elements/metrics.dart
index cb5282b..12a3ef6 100644
--- a/runtime/observatory/lib/src/elements/metrics.dart
+++ b/runtime/observatory/lib/src/elements/metrics.dart
@@ -6,217 +6,153 @@
 
 import 'dart:async';
 import 'dart:html';
-import 'observatory_element.dart';
-import 'package:charted/charted.dart';
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/metric/details.dart';
+import 'package:observatory/src/elements/metric/graph.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
 
-@CustomTag('metrics-page')
-class MetricsPageElement extends ObservatoryElement {
+class MetricsPageElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<MetricsPageElement>('metrics-page',
+                                                   dependencies: const [
+                                                     MetricDetailsElement.tag,
+                                                     MetricGraphElement.tag,
+                                                     NavTopMenuElement.tag,
+                                                     NavVMMenuElement.tag,
+                                                     NavIsolateMenuElement.tag,
+                                                     NavRefreshElement.tag,
+                                                     NavNotifyElement.tag,
+                                                   ]);
+
+  RenderingScheduler<MetricsPageElement> _r;
+
+  Stream<RenderedEvent<MetricsPageElement>> get onRendered => _r.onRendered;
+
+  M.VM _vm;
+  M.IsolateRef _isolate;
+  M.EventRepository _events;
+  M.NotificationRepository _notifications;
+  M.MetricRepository _metrics;
+  List<M.Metric> _available;
+  M.Metric _selected;
+
+
+  M.VMRef get vm => _vm;
+  M.IsolateRef get isolate => _isolate;
+  M.NotificationRepository get notifications => _notifications;
+
+  factory MetricsPageElement(M.VM vm, M.IsolateRef isolate,
+                            M.EventRepository events,
+                            M.NotificationRepository notifications,
+                            M.MetricRepository metrics,
+                            {RenderingQueue queue}) {
+    assert(vm != null);
+    assert(isolate != null);
+    assert(events != null);
+    assert(notifications != null);
+    MetricsPageElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._vm = vm;
+    e._isolate = isolate;
+    e._events = events;
+    e._notifications = notifications;
+    e._metrics = metrics;
+    return e;
+  }
+
   MetricsPageElement.created() : super.created();
 
-  @observable MetricsPage page;
-  @observable Isolate isolate;
-  @observable ServiceMetric selectedMetric;
-
-  void _autoPickSelectedMetric() {
-    if (selectedMetric != null) {
-      return;
-    }
-    // Attempt to pick the last selected metric.
-    if ((isolate != null) && (page != null) &&
-        (page.selectedMetricId != null)) {
-      selectedMetric = isolate.dartMetrics[page.selectedMetricId];
-      if (selectedMetric != null) {
-        return;
-      }
-      selectedMetric = isolate.nativeMetrics[page.selectedMetricId];
-    }
-    if ((selectedMetric == null) && (isolate != null)) {
-      var values = isolate.dartMetrics.values.toList();
-      if ((values != null) && (values.length > 0)) {
-        // Fall back and pick the first isolate metric.
-        selectedMetric = values.first;
-      }
-      if (selectedMetric != null) {
-        return;
-      }
-      values = isolate.nativeMetrics.values.toList();
-      if ((values != null) && (values.length > 0)) {
-        // Fall back and pick the first isolate metric.
-        selectedMetric = values.first;
-      }
-    }
-  }
-
-  void attached() {
-    _autoPickSelectedMetric();
-  }
-
-  void isolateChanged(oldValue) {
-    if (isolate != null) {
-      isolate.refreshMetrics().then((_) {
-        _autoPickSelectedMetric();
-      });
-    }
-  }
-
-  Future refresh() {
-    return isolate.refreshMetrics();
-  }
-
-  void selectMetric(Event e, var detail, Element target) {
-    String id = target.attributes['data-id'];
-    selectedMetric = isolate.dartMetrics[id];
-    if (selectedMetric == null) {
-      // Check VM metrics.
-      selectedMetric = isolate.nativeMetrics[id];
-    }
-    if (selectedMetric != null) {
-      page.selectedMetricId = id;
-    } else {
-      page.selectedMetricId = null;
-    }
-  }
-}
-
-@CustomTag('metric-details')
-class MetricDetailsElement extends ObservatoryElement {
-  MetricDetailsElement.created() : super.created();
-  @published MetricsPage page;
-  @published ServiceMetric metric;
-
-  int _findIndex(SelectElement element, int value) {
-    if (element == null) {
-      return null;
-    }
-    for (var i = 0; i < element.options.length; i++) {
-      var optionElement = element.options[i];
-      int optionValue = int.parse(optionElement.value);
-      if (optionValue == value) {
-        return i;
-      }
-    }
-    return null;
-  }
-
-  void attached() {
+  @override
+  attached() {
     super.attached();
-    _updateSelectedIndexes();
+    _r.enable();
+    _refresh();
   }
 
-  void _updateSelectedIndexes() {
-    if (metric == null) {
-      return;
+  @override
+  detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
+  }
+
+  void render() {
+    children = [
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('metrics'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) {
+              e.element.disabled = true;
+              _refresh();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
+      new DivElement()..classes = ['content-centered-big']
+        ..children = [
+          new HeadingElement.h2()..text = 'Metrics',
+          new HRElement(),
+          new DivElement()..classes = ['memberList']
+            ..children = [
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'Metric',
+                  new DivElement()..classes = ['memberValue']
+                    ..children = _available == null
+                      ? [new SpanElement()..text = 'Loading..']
+                      : _createMetricSelect()
+                ]
+            ],
+          new HRElement(),
+          new DivElement()
+            ..children = _selected == null ? const []
+              : [
+                new MetricDetailsElement(_isolate, _selected, _metrics,
+                                         queue: _r.queue)
+              ],
+          new HRElement(),
+          new DivElement()..classes = ['graph']
+            ..children = _selected == null ? const []
+              : [
+                new MetricGraphElement(_isolate, _selected, _metrics,
+                                       queue: _r.queue)
+              ]
+        ],
+    ];
+  }
+
+  Future _refresh() async {
+    _available = (await _metrics.list(_isolate)).toList();
+    if (!_available.contains(_selected)) {
+      _selected = _available.first;
     }
-    SelectElement refreshRateElement = shadowRoot.querySelector('#refreshrate');
-    if (refreshRateElement == null) {
-      // Race between shadowRoot setup and events.
-      return;
-    }
-    int period = 0;
-    if (metric.poller != null) {
-      period = metric.poller.pollPeriod.inMilliseconds;
-    }
-    var index = _findIndex(refreshRateElement, period);
-    assert(index != null);
-    refreshRateElement.selectedIndex = index;
-    SelectElement bufferSizeElement = shadowRoot.querySelector('#buffersize');
-    index = _findIndex(bufferSizeElement, metric.sampleBufferSize);
-    assert(index != null);
-    bufferSizeElement.selectedIndex = index;
+    _r.dirty();
   }
 
-  metricChanged(oldValue) {
-    _updateSelectedIndexes();
-  }
-
-  void refreshRateChange(Event e, var detail, Element target) {
-    var value = int.parse((target as SelectElement).value);
-    if (metric == null) {
-      return;
-    }
-    page.setRefreshPeriod(value, metric);
-  }
-
-  void sampleBufferSizeChange(Event e, var detail, Element target) {
-    var value = int.parse((target as SelectElement).value);
-    if (metric == null) {
-      return;
-    }
-    metric.sampleBufferSize = value;
-  }
-}
-
-@CustomTag('metrics-graph')
-class MetricsGraphElement extends ObservatoryElement {
-  MetricsGraphElement.created() : super.created();
-
-  HtmlElement _wrapper;
-  HtmlElement _areaHost;
-  CartesianArea _area;
-  ChartData _data;
-  final _columns = [
-      new ChartColumnSpec(label: 'Time', type: ChartColumnSpec.TYPE_TIMESTAMP),
-      new ChartColumnSpec(label: 'Value', formatter: (v) => v.toString())
-  ];
-  final _rows = [[0, 1000000.0]];
-
-  @published ServiceMetric metric;
-  @observable Isolate isolate;
-
-  void attached() {
-    super.attached();
-    // Redraw once a second.
-    pollPeriod = new Duration(seconds: 1);
-    _reset();
-  }
-
-  void onPoll() {
-    if (metric == null) {
-      return;
-    }
-    _update();
-    _draw();
-  }
-
-  void _reset() {
-    _rows.clear();
-    _wrapper = shadowRoot.querySelector('#metric-chart');
-    assert(_wrapper != null);
-    _areaHost = _wrapper.querySelector('.chart-host');
-    assert(_areaHost != null);
-    _areaHost.children.clear();
-    var series = new ChartSeries("one", [1], new LineChartRenderer());
-    var config = new ChartConfig([series], [0]);
-    config.minimumSize = new Rect(800, 600);
-    _data = new ChartData(_columns, _rows);
-    _area = new CartesianArea(_areaHost,
-                              _data,
-                              config,
-                              state: new ChartState());
-  }
-
-  void _update() {
-    _rows.clear();
-    for (var i = 0; i < metric.samples.length; i++) {
-      var sample = metric.samples[i];
-      _rows.add([sample.time.millisecondsSinceEpoch, sample.value]);
-    }
-  }
-
-  void _draw() {
-    if (_rows.length < 2) {
-      return;
-    }
-    _area.data = new ChartData(_columns, _rows);
-    _area.draw();
-  }
-
-  metricChanged(oldValue) {
-    if (oldValue != metric) {
-      _reset();
-    }
+  List<Element> _createMetricSelect() {
+    var s;
+    return [
+      s = new SelectElement()
+        ..value = _selected.name
+        ..children = _available.map((metric) {
+            return new OptionElement(value: metric.name,
+                selected: _selected == metric)
+              ..text = metric.name;
+          }).toList(growable: false)
+        ..onChange.listen((_) {
+            _selected = _available[s.selectedIndex];
+            _r.dirty();
+          })
+    ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/metrics.html b/runtime/observatory/lib/src/elements/metrics.html
deleted file mode 100644
index a82cea0..0000000
--- a/runtime/observatory/lib/src/elements/metrics.html
+++ /dev/null
@@ -1,147 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="metrics-page">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      ul li:hover:not(.selected) {
-        background-color: #FFF3E3;
-      }
-      .selected {
-        background-color: #0489c3;
-      }
-      .graph {
-        min-height: 600px;
-      }
-    </style>
-    <nav-bar>
-      <top-nav-menu></top-nav-menu>
-      <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
-      <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
-      <nav-menu link="{{ makeLink('/metrics', isolate) }}" anchor="metrics" last="{{ true }}"></nav-menu>
-
-      <nav-refresh callback="{{ refresh }}"></nav-refresh>
-      <nav-notify notifications="{{ app.notifications }}"></nav-notify>
-    </nav-bar>
-    <div class="flex-row">
-      <div class="flex-item-20-percent">
-        <ul>
-          <template repeat="{{ metric in isolate.dartMetrics.values }}">
-            <template if="{{ metric == selectedMetric }}">
-              <li class="selected">
-                {{ metric.name }}
-              </li>
-            </template>
-            <template if="{{ metric != selectedMetric }}">
-              <li on-click="{{ selectMetric }}" data-id="{{ metric.id }}">
-                {{ metric.name }}
-              </li>
-            </template>
-          </template>
-          <template repeat="{{ metric in isolate.nativeMetrics.values }}">
-            <template if="{{ metric == selectedMetric }}">
-              <li class="selected">
-                {{ metric.name }}
-              </li>
-            </template>
-            <template if="{{ metric != selectedMetric }}">
-              <li on-click="{{ selectMetric }}" data-id="{{ metric.id }}">
-                {{ metric.name }}
-              </li>
-            </template>
-          </template>
-        </ul>
-      </div>
-      <div class="flex-item-80-percent">
-        <metrics-graph isolate="{{ isolate }}" metric="{{ selectedMetric }}">
-        </metrics-graph>
-        <div>
-          <metric-details page="{{ page }}" metric="{{ selectedMetric }}">
-          </metric-details>
-        </div>
-      </div>
-    </div>
-  </template>
-</polymer-element>
-
-<polymer-element name="metric-details">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <div class="content-centered">
-      <div class="memberList">
-        <div class="memberItem">
-          <div class="memberName">name</div>
-          <div class="memberValue">{{ metric.name }}</div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">description</div>
-          <div class="memberValue">{{ metric.description }}</div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">current value</div>
-          <div class="memberValue">{{ metric.value }}</div>
-        </div>
-        <template if="{{ (metric != null) && (metric.min != null) }}">
-          <div class="memberItem">
-            <div class="memberName">minimum</div>
-            <div class="memberValue">{{ metric.min }}</div>
-          </div>
-        </template>
-        <template if="{{ (metric != null) && (metric.max != null) }}">
-          <div class="memberItem">
-            <div class="memberName">maximum</div>
-            <div class="memberValue">{{ metric.max }}</div>
-          </div>
-        </template>
-        <div class="memberItem">
-          <div class="memberName">refresh rate</div>
-          <div class="memberValue">
-            <select id="refreshrate" on-change="{{ refreshRateChange }}">
-              <!-- These must be kept in sync with POLL_PERIODS in MetricsPage
-                   in object.dart -->
-              <option value="8000">Every eight seconds</option>
-              <option value="4000">Every four seconds</option>
-              <option value="2000">Every two seconds</option>
-              <option value="1000">Once a second</option>
-              <option value="100">Ten times per second</option>
-              <option value="0" selected="selected">Never</option>
-            </select>
-          </div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">sample buffer size</div>
-          <div class="memberValue">
-            <select id="buffersize" on-change="{{ sampleBufferSizeChange }}">
-              <option value="10">10</option>
-              <option value="100" selected="selected">100</option>
-              <option value="1000">1000</option>
-            </select>
-          </div>
-        </div>
-      </div>
-    </div>
-  </template>
-</polymer-element>
-
-<polymer-element name="metrics-graph">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <link rel="stylesheet" href="../../../../packages/charted/charts/themes/quantum_theme.css">
-    <style>
-.chart-wrapper {
-  padding: 40px;
-  width: 800px;
-}
-.chart-host-wrapper {
-  height: 300px;
-}
-    </style>
-    <div class="chart-wrapper" id="metric-chart">
-        <div class="chart-host-wrapper">
-            <div class="chart-host" dir="ltr"></div>
-        </div>
-    </div>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="metrics.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/nav/bar.dart b/runtime/observatory/lib/src/elements/nav/bar.dart
deleted file mode 100644
index b175ba6..0000000
--- a/runtime/observatory/lib/src/elements/nav/bar.dart
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-
-class NavBarElement extends HtmlElement implements Renderable {
-  static final StyleElement _style = () {
-      var style = new StyleElement();
-      style.text = 'nav.nav-bar {'
-                     'line-height: normal;'
-                     'position: fixed;'
-                     'top: 0;'
-                     'width: 100%;'
-                     'z-index: 1000;'
-                     '}'
-                   'nav.nav-bar > ul {'
-                     'display: inline-table;'
-                     'position: relative;'
-                     'list-style: none;'
-                     'padding-left: 0;'
-                     'margin: 0;'
-                     'width: 100%;'
-                     'z-index: 1000;'
-                     'font: 400 16px \'Montserrat\', sans-serif;'
-                     'color: white;'
-                     'background-color: #0489c3;'
-                   '}';
-      return style;
-  }();
-
-  static const tag = const Tag<NavBarElement>('nav-bar');
-
-  RenderingScheduler _r;
-
-  Stream<RenderedEvent<NavBarElement>> get onRendered => _r.onRendered;
-
-  factory NavBarElement({RenderingQueue queue}) {
-    NavBarElement e = document.createElement(tag.name);
-    e._r = new RenderingScheduler(e, queue: queue);
-    return e;
-  }
-
-  NavBarElement.created() : super.created() {
-    // TODO(cbernaschina) remove when no more needed.
-    _r = new RenderingScheduler(this);
-    createShadowRoot();
-  }
-
-  @override
-  void attached() { super.attached(); _r.enable(); }
-
-  @override
-  void detached() {
-    super.detached(); _r.disable(notify: true);
-    shadowRoot.children = [];
-  }
-
-  void render() {
-    shadowRoot.children = [
-      _style.clone(true),
-      document.createElement('nav')
-        ..classes = ['nav-bar']
-        ..children = [
-          new UListElement()
-            ..children = [
-              new ContentElement()
-            ],
-        ],
-      new DivElement()
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/class_menu.dart b/runtime/observatory/lib/src/elements/nav/class_menu.dart
index d8ed510..6c13336 100644
--- a/runtime/observatory/lib/src/elements/nav/class_menu.dart
+++ b/runtime/observatory/lib/src/elements/nav/class_menu.dart
@@ -5,41 +5,43 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M show IsolateRef, ClassRef;
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 
 class NavClassMenuElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<NavClassMenuElement>('nav-class-menu',
-                     dependencies: const [NavMenuElement.tag]);
+  static const tag = const Tag<NavClassMenuElement>('nav-class-menu');
 
   RenderingScheduler _r;
 
   Stream<RenderedEvent<NavClassMenuElement>> get onRendered => _r.onRendered;
 
-  bool _last;
   M.IsolateRef _isolate;
   M.ClassRef _cls;
-  bool get last => _last;
+  Iterable<Element> _content = const [];
+
   M.IsolateRef get isolate => _isolate;
   M.ClassRef get cls => _cls;
-  set last(bool value) => _last = _r.checkAndReact(_last, value);
+  Iterable<Element> get content => _content;
+
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
 
   factory NavClassMenuElement(M.IsolateRef isolate, M.ClassRef cls,
-      {bool last: false, RenderingQueue queue}) {
+      {RenderingQueue queue}) {
     assert(isolate != null);
     assert(cls != null);
-    assert(last != null);
     NavClassMenuElement e = document.createElement(tag.name);
     e._r = new RenderingScheduler(e, queue: queue);
     e._isolate = isolate;
     e._cls = cls;
-    e._last = last;
     return e;
   }
 
-  NavClassMenuElement.created() : super.created() { createShadowRoot(); }
+  NavClassMenuElement.created() : super.created();
 
   @override
   void attached() {
@@ -50,15 +52,14 @@
   @override
   void detached() {
     super.detached();
+    children = [];
     _r.disable(notify: true);
-    shadowRoot.children = [];
   }
 
   void render() {
-    shadowRoot.children = [
-      new NavMenuElement(cls.name, last: last, queue: _r.queue,
-          link: Uris.inspect(isolate, object: cls))
-        ..children = [new ContentElement()]
+    children = [
+      navMenu(cls.name, content: _content,
+              link: Uris.inspect(isolate, object: cls))
     ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/nav/class_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/class_menu_wrapper.dart
deleted file mode 100644
index 42a65de..0000000
--- a/runtime/observatory/lib/src/elements/nav/class_menu_wrapper.dart
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/class_menu.dart';
-
-@bindable
-class NavClassMenuElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavClassMenuElementWrapper>(const {
-      'last': #last, 'cls': #cls
-    });
-
-  static const tag =
-    const Tag<NavClassMenuElementWrapper>('class-nav-menu');
-
-  bool _last = false;
-  Class _cls;
-
-  bool get last => _last;
-  Class get cls => _cls;
-  
-  set last(bool value) {
-    _last = value;
-    render();
-  }
-  set cls(Class value) {
-    _cls = value;
-    render();
-  }
-
-  NavClassMenuElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _last = _getBoolAttribute('last');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_cls == null || _last == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavClassMenuElement(cls.isolate, cls, last: last,
-                                 queue: ObservatoryApplication.app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-
-  bool _getBoolAttribute(String name) {
-    final String value = getAttribute(name);
-    return !(value == null || value == 'false');
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/isolate_menu.dart b/runtime/observatory/lib/src/elements/nav/isolate_menu.dart
index d9f82c9..a5b64f1 100644
--- a/runtime/observatory/lib/src/elements/nav/isolate_menu.dart
+++ b/runtime/observatory/lib/src/elements/nav/isolate_menu.dart
@@ -6,49 +6,45 @@
 import 'dart:async';
 import 'package:observatory/models.dart' as M
   show IsolateRef, EventRepository;
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/menu_item.dart';
 
 class NavIsolateMenuElement extends HtmlElement implements Renderable {
   static const tag = const Tag<NavIsolateMenuElement>('nav-isolate-menu',
-                     dependencies: const [NavMenuElement.tag,
-                                          NavMenuItemElement.tag]);
+                     dependencies: const [NavMenuItemElement.tag]);
 
   RenderingScheduler _r;
 
   Stream<RenderedEvent<NavIsolateMenuElement>> get onRendered => _r.onRendered;
 
-  bool _last;
   M.IsolateRef _isolate;
   M.EventRepository _events;
   StreamSubscription _updatesSubscription;
+  Iterable<Element> _content = const [];
 
-  bool get last => _last;
   M.IsolateRef get isolate => _isolate;
+  Iterable<Element> get content => _content;
 
-  set last(bool value) => _last = _r.checkAndReact(_last, value);
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
 
   factory NavIsolateMenuElement(M.IsolateRef isolate,
-      M.EventRepository events, {bool last: false,
-      RenderingQueue queue}) {
+      M.EventRepository events, {RenderingQueue queue}) {
     assert(isolate != null);
     assert(events != null);
-    assert(last != null);
     NavIsolateMenuElement e = document.createElement(tag.name);
     e._r = new RenderingScheduler(e, queue: queue);
     e._isolate = isolate;
-    e._last = last;
     e._events = events;
     return e;
   }
 
-  NavIsolateMenuElement.created() : super.created() {
-    _r = new RenderingScheduler(this);
-    createShadowRoot();
-  }
+  NavIsolateMenuElement.created() : super.created();
 
   @override
   void attached() {
@@ -62,42 +58,41 @@
   @override
   void detached() {
     super.detached();
+    children = [];
     _r.disable(notify: true);
-    shadowRoot.children = [];
     assert(_updatesSubscription != null);
     _updatesSubscription.cancel();
     _updatesSubscription = null;
   }
 
   void render() {
-    shadowRoot.children = [
-      new NavMenuElement(isolate.name, last: last, queue: _r.queue,
+    final content = [
+      new NavMenuItemElement('debugger', queue: _r.queue,
+          link: Uris.debugger(isolate)),
+      new NavMenuItemElement('class hierarchy', queue: _r.queue,
+          link: Uris.classTree(isolate)),
+      new NavMenuItemElement('cpu profile', queue: _r.queue,
+          link: Uris.cpuProfiler(isolate)),
+      new NavMenuItemElement('cpu profile (table)', queue: _r.queue,
+          link: Uris.cpuProfilerTable(isolate)),
+      new NavMenuItemElement('allocation profile', queue: _r.queue,
+          link: Uris.allocationProfiler(isolate)),
+      new NavMenuItemElement('heap map', queue: _r.queue,
+          link: Uris.heapMap(isolate)),
+      new NavMenuItemElement('metrics', queue: _r.queue,
+          link: Uris.metrics(isolate)),
+      new NavMenuItemElement('heap snapshot', queue: _r.queue,
+          link: Uris.heapSnapshot(isolate)),
+      new NavMenuItemElement('persistent handles', queue: _r.queue,
+          link: Uris.persistentHandles(isolate)),
+      new NavMenuItemElement('ports', queue: _r.queue,
+          link: Uris.ports(isolate)),
+      new NavMenuItemElement('logging', queue: _r.queue,
+          link: Uris.logging(isolate)),
+    ]..addAll(_content);
+    children = [
+      navMenu(isolate.name, content: content,
           link: Uris.inspect(isolate))
-        ..children = [
-          new NavMenuItemElement('debugger', queue: _r.queue,
-              link: Uris.debugger(isolate)),
-          new NavMenuItemElement('class hierarchy', queue: _r.queue,
-              link: Uris.classTree(isolate)),
-          new NavMenuItemElement('cpu profile', queue: _r.queue,
-              link: Uris.cpuProfiler(isolate)),
-          new NavMenuItemElement('cpu profile (table)', queue: _r.queue,
-              link: Uris.cpuProfilerTable(isolate)),
-          new NavMenuItemElement('allocation profile', queue: _r.queue,
-              link: Uris.allocationProfiler(isolate)),
-          new NavMenuItemElement('heap map', queue: _r.queue,
-              link: Uris.heapMap(isolate)),
-          new NavMenuItemElement('metrics', queue: _r.queue,
-              link: Uris.metrics(isolate)),
-          new NavMenuItemElement('heap snapshot', queue: _r.queue,
-              link: Uris.heapSnapshot(isolate)),
-          new NavMenuItemElement('persistent handles', queue: _r.queue,
-              link: Uris.persistentHandles(isolate)),
-          new NavMenuItemElement('ports', queue: _r.queue,
-              link: Uris.ports(isolate)),
-          new NavMenuItemElement('logging', queue: _r.queue,
-              link: Uris.logging(isolate)),
-          new ContentElement()
-        ]
     ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/nav/isolate_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/isolate_menu_wrapper.dart
deleted file mode 100644
index ff4e1ed..0000000
--- a/runtime/observatory/lib/src/elements/nav/isolate_menu_wrapper.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/isolate_menu.dart';
-
-@bindable
-class NavIsolateMenuElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavIsolateMenuElementWrapper>(const {
-      'last':  #last, 'isolate': #isolate
-    });
-
-  static const tag =
-    const Tag<NavIsolateMenuElementWrapper>('isolate-nav-menu');
-
-  bool _last = false;
-  Isolate _isolate;
-  
-  bool get last => _last;
-  Isolate get isolate => _isolate;
-
-  set last(bool value) {
-    _last = value;
-    render();
-  }
-  set isolate(Isolate value) {
-    _isolate = value;
-    render();
-  }
-
-  NavIsolateMenuElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _last = _getBoolAttribute('last');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_isolate == null || _last == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavIsolateMenuElement(_isolate, app.events, last: _last,
-          queue: app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-
-  ObservatoryApplication get app => ObservatoryApplication.app;
-
-  bool _getBoolAttribute(String name) {
-    final String value = getAttribute(name);
-    return !(value == null || value == 'false');
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/library_menu.dart b/runtime/observatory/lib/src/elements/nav/library_menu.dart
index 36160d6..783adf3 100644
--- a/runtime/observatory/lib/src/elements/nav/library_menu.dart
+++ b/runtime/observatory/lib/src/elements/nav/library_menu.dart
@@ -5,43 +5,43 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M show IsolateRef, LibraryRef;
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 
 class NavLibraryMenuElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<NavLibraryMenuElement>('nav-library-menu',
-                     dependencies: const [NavMenuElement.tag]);
+  static const tag = const Tag<NavLibraryMenuElement>('nav-library-menu');
 
   RenderingScheduler _r;
 
   Stream<RenderedEvent<NavLibraryMenuElement>> get onRendered => _r.onRendered;
 
-  bool _last;
   M.IsolateRef _isolate;
   M.LibraryRef _library;
+  Iterable<Element> _content = const [];
 
-  bool get last => _last;
   M.IsolateRef get isolate => _isolate;
   M.LibraryRef get library => _library;
-  
-  set last(bool value) => _last = _r.checkAndReact(_last, value);
+  Iterable<Element> get content => _content;
+
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
 
   factory NavLibraryMenuElement(M.IsolateRef isolate, M.LibraryRef library,
-      {bool last: false, RenderingQueue queue}) {
+      {RenderingQueue queue}) {
     assert(isolate != null);
     assert(library != null);
-    assert(last != null);
     NavLibraryMenuElement e = document.createElement(tag.name);
     e._r = new RenderingScheduler(e, queue: queue);
     e._isolate = isolate;
     e._library = library;
-    e._last = last;
     return e;
   }
 
-  NavLibraryMenuElement.created() : super.created() { createShadowRoot(); }
+  NavLibraryMenuElement.created() : super.created();
 
   @override
   void attached() {
@@ -52,15 +52,14 @@
   @override
   void detached() {
     super.detached();
+    children = [];
     _r.disable(notify: true);
-    shadowRoot.children = [];
   }
 
   void render() {
-    shadowRoot.children = [
-      new NavMenuElement(library.name, last: last, queue: _r.queue,
+    children = [
+      navMenu(library.name, content: _content,
                 link: Uris.inspect(isolate, object: library).toString())
-        ..children = [new ContentElement()]
     ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/nav/library_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/library_menu_wrapper.dart
deleted file mode 100644
index 8db0347..0000000
--- a/runtime/observatory/lib/src/elements/nav/library_menu_wrapper.dart
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/library_menu.dart';
-
-@bindable
-class NavLibraryMenuElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavLibraryMenuElementWrapper>(const {
-      'last': #last, 'library': #library
-    });
-
-  static const tag =
-    const Tag<NavLibraryMenuElementWrapper>('library-nav-menu');
-
-  bool _last = false;
-  Library _library;
-
-  bool get last => _last;
-  Library get library => _library;
-  
-  set last(bool value) {
-    _last = value;
-    render();
-  }
-  set library(Library value) {
-    _library = value;
-    render();
-  }
-
-  NavLibraryMenuElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _last = _getBoolAttribute('last');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_library == null || _last == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavLibraryMenuElement(library.isolate, library, last: last,
-                                 queue: ObservatoryApplication.app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-
-  bool _getBoolAttribute(String name) {
-    final String value = getAttribute(name);
-    return !(value == null || value == 'false');
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/menu.dart b/runtime/observatory/lib/src/elements/nav/menu.dart
deleted file mode 100644
index 2624ad7..0000000
--- a/runtime/observatory/lib/src/elements/nav/menu.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-
-class NavMenuElement extends HtmlElement implements Renderable {
-  static final StyleElement _style = () {
-      var style = new StyleElement();
-      style.text = '''li.nav-menu_label, li.nav-menu_spacer {
-                        float: left;
-                      }
-                      li.nav-menu_label > a, li.nav-menu_spacer {
-                        display: block;
-                        padding: 12px 8px;
-                        color: White;
-                        text-decoration: none;
-                      }
-                      li.nav-menu_label:hover {
-                        background: #455;
-                      }
-                      li.nav-menu_label > ul {
-                        display: none;
-                        position: absolute;
-                        top: 98%;
-                        list-style: none;
-                        margin: 0;
-                        padding: 0;
-                        width: auto;
-                        z-index: 1000;
-                        font: 400 16px \'Montserrat\', sans-serif;
-                        color: white;
-                        background: #567;
-                      }
-                      li.nav-menu_label > ul:after {
-                        content: ""; clear: both; display: block;
-                      }
-                      li.nav-menu_label:hover > ul {
-                        display: block;
-                      }''';
-      return style;
-  }();
-
-  static const tag = const Tag<NavMenuElement>('nav-menu-wrapped');
-
-  RenderingScheduler _r;
-
-  Stream<RenderedEvent<NavMenuElement>> get onRendered => _r.onRendered;
-
-  String _label;
-  String _link;
-  bool _last;
-
-  String get label => _label;
-  String get link => _link;
-  bool get last => _last;
-  
-  set label(String value) => _label = _r.checkAndReact(_label, value);
-  set link(String value) => _link = _r.checkAndReact(_link, value);
-  set last(bool value) => _last = _r.checkAndReact(_link, value);
-
-  factory NavMenuElement(String label, {String link, bool last: false,
-                             RenderingQueue queue}) {
-    assert(label != null);
-    assert(last != null);
-    NavMenuElement e = document.createElement(tag.name);
-    e._r = new RenderingScheduler(e, queue: queue);
-    e._label = label;
-    e._link = link;
-    e._last = last;
-    return e;
-  }
-
-  NavMenuElement.created() : super.created() { createShadowRoot(); }
-
-  @override
-  void attached() {
-    super.attached();
-    _r.enable();
-  }
-
-  @override
-  void detached() {
-    super.detached();
-    _r.disable(notify: true);
-    shadowRoot.children = [];
-  }
-
-  void render() {
-    List<Element> children = [
-      _style.clone(true),
-      new LIElement()
-        ..classes = ['nav-menu_label']
-        ..children = [
-          new AnchorElement(href: link)
-            ..text = label,
-          new UListElement()
-            ..children = [
-              new ContentElement()
-            ]
-        ]
-    ];
-    if (!last) {
-      children.add(
-        new LIElement()
-          ..classes = ['nav-menu_spacer']
-          ..innerHtml = '&gt;'
-      );
-    }
-    shadowRoot.children = children;
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/menu_item.dart b/runtime/observatory/lib/src/elements/nav/menu_item.dart
index 03ced3d..5be6723 100644
--- a/runtime/observatory/lib/src/elements/nav/menu_item.dart
+++ b/runtime/observatory/lib/src/elements/nav/menu_item.dart
@@ -8,46 +8,7 @@
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 
 class NavMenuItemElement extends HtmlElement implements Renderable {
-  static final StyleElement _style = () {
-      var style = new StyleElement();
-      style.text = '''li.nav-menu-item {
-                        float: none;
-                        border-top: 1px solid #677;
-                        border-bottom: 1px solid #556; position: relative;
-                      }
-                      li.nav-menu-item:hover {
-                        background: #455;
-                      }
-                      li.nav-menu-item > a {
-                        display: block;
-                        padding: 12px 12px;
-                        color: white;
-                        text-decoration: none;
-                      }
-                      li.nav-menu-item > ul {
-                        display: none;
-                        position: absolute;
-                        top:0;
-                        left: 100%;
-                        list-style: none;
-                        padding: 0;
-                        margin-left: 0;
-                        width: auto;
-                        z-index: 1000;
-                        font: 400 16px \'Montserrat\', sans-serif;
-                        color: white;
-                        background: #567;
-                      }
-                      li.nav-menu-item > ul:after {
-                        content: ""; clear: both; display: block;
-                      }
-                      li.nav-menu-item:hover > ul {
-                        display: block;
-                      }''';
-      return style;
-  }();
-
-  static const tag = const Tag<NavMenuItemElement>('nav-menu-item-wrapped');
+  static const tag = const Tag<NavMenuItemElement>('nav-menu-item');
 
   RenderingScheduler _r;
 
@@ -55,12 +16,18 @@
 
   String _label;
   String _link;
+  Iterable<Element> _content = const [];
 
   String get label => _label;
   String get link => _link;
-  
+  Iterable<Element> get content => _content;
+
   set label(String value) => _label = _r.checkAndReact(_label, value);
   set link(String value) => _link = _r.checkAndReact(_link, value);
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
 
 
   factory NavMenuItemElement(String label, {String link,
@@ -73,7 +40,7 @@
     return e;
   }
 
-  NavMenuItemElement.created() : super.created() { createShadowRoot(); }
+  NavMenuItemElement.created() : super.created();
 
   @override
   void attached() {
@@ -85,21 +52,18 @@
   void detached() {
     super.detached();
     _r.disable(notify: true);
-    shadowRoot.children = [];
+    children = [];
   }
 
   void render() {
-    shadowRoot.children = [
-      _style.clone(true),
+    children = [
       new LIElement()
         ..classes = ['nav-menu-item']
         ..children = [
           new AnchorElement(href: link)
             ..text = label,
           new UListElement()
-            ..children = [
-              new ContentElement()
-            ]
+            ..children = _content
         ]
     ];
   }
diff --git a/runtime/observatory/lib/src/elements/nav/menu_item_wrapper.dart b/runtime/observatory/lib/src/elements/nav/menu_item_wrapper.dart
deleted file mode 100644
index e00699c..0000000
--- a/runtime/observatory/lib/src/elements/nav/menu_item_wrapper.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/menu_item.dart';
-
-@bindable
-class NavMenuItemElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavMenuItemElementWrapper>(const {
-      'anchor': #anchor, 'link': #link
-    });
-
-  static const tag =
-    const Tag<NavMenuItemElementWrapper>('nav-menu-item');
-
-  String _anchor;
-  String _link;
-
-  String get anchor => _anchor;
-  String get link => _link;
-  
-  set anchor(String value) {
-    _anchor = value;
-    render();
-  }
-  set link(String value) {
-    _link = value;
-    render();
-  }
-
-  NavMenuItemElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _anchor = getAttribute('anchor');
-    _link = getAttribute('link');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_anchor == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavMenuItemElement(_anchor, link: '#$link',
-                                 queue: ObservatoryApplication.app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/menu_wrapper.dart
deleted file mode 100644
index 3b287fe..0000000
--- a/runtime/observatory/lib/src/elements/nav/menu_wrapper.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
-
-@bindable
-class NavMenuElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavMenuElementWrapper>(const {
-      'anchor': #anchor, 'link': #link, 'last': #last
-    });
-
-  static const tag =
-    const Tag<NavMenuElementWrapper>('nav-menu');
-
-  String _anchor = '---';
-  String _link;
-  bool _last = false;
-
-  String get anchor => _anchor;
-  String get link => _link;
-  bool get last => _last;
-  
-  set anchor(String value) {
-    _anchor = value;
-    render();
-  }
-  set link(String value) {
-    _link = value;
-    render();
-  }
-  set last(bool value) {
-    _last = value;
-    render();
-  }
-
-  NavMenuElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _anchor = getAttribute('anchor');
-    _link = getAttribute('link');
-    _last = _getBoolAttribute('last');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_anchor == null || _last == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavMenuElement(_anchor, link: '#$_link', last: last,
-                                 queue: ObservatoryApplication.app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-
-  bool _getBoolAttribute(String name) {
-    final String value = getAttribute(name);
-    return !(value == null || value == 'false');
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/notify.dart b/runtime/observatory/lib/src/elements/nav/notify.dart
index 1566a04..5411e11 100644
--- a/runtime/observatory/lib/src/elements/nav/notify.dart
+++ b/runtime/observatory/lib/src/elements/nav/notify.dart
@@ -11,7 +11,7 @@
 import 'package:observatory/src/elements/nav/notify_exception.dart';
 
 class NavNotifyElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<NavNotifyElement>('nav-notify-wrapped',
+  static const tag = const Tag<NavNotifyElement>('nav-notify',
           dependencies: const [ NavNotifyEventElement.tag,
                                 NavNotifyExceptionElement.tag ]);
 
@@ -25,7 +25,7 @@
   bool _notifyOnPause;
 
   bool get notifyOnPause => _notifyOnPause;
-  
+
   set notifyOnPause(bool value) =>
       _notifyOnPause = _r.checkAndReact(_notifyOnPause, value);
 
diff --git a/runtime/observatory/lib/src/elements/nav/notify_wrapper.dart b/runtime/observatory/lib/src/elements/nav/notify_wrapper.dart
deleted file mode 100644
index 58dbf39..0000000
--- a/runtime/observatory/lib/src/elements/nav/notify_wrapper.dart
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/notify.dart';
-
-@bindable
-class NavNotifyElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavNotifyElementWrapper>(const {
-      'notifications': #notifications, 'notifyOnPause': #notifyOnPause
-    });
-
-  static const tag = const Tag<NavNotifyElementWrapper>('nav-notify');
-
-  NotificationRepository _notifications;
-  bool _notifyOnPause = true;
-
-  NotificationRepository get notifications => _notifications;
-  bool get notifyOnPause => _notifyOnPause;
-  
-  set notifications(NotificationRepository value) {
-    _notifications = value;
-    render();
-  }
-  set notifyOnPause(bool value) {
-    _notifyOnPause = value;
-    render();
-  }
-
-  NavNotifyElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_notifications == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''nav-notify-wrapped > div {
-          float: right;
-        }
-        nav-notify-wrapped > div > div {
-          display: block;
-          position: absolute;
-          top: 98%;
-          right: 0;
-          margin: 0;
-          padding: 0;
-          width: auto;
-          z-index: 1000;
-          background: none;
-        }
-
-        /* nav-exception & nav-event */
-
-        nav-exception > div, nav-event > div {
-          position: relative;
-          padding: 16px;
-          margin-top: 10px;
-          margin-right: 10px;
-          padding-right: 25px;
-          width: 500px;
-          color: #ddd;
-          background: rgba(0,0,0,.6);
-          border: solid 2px white;
-          box-shadow: 0 0 5px black;
-          border-radius: 5px;
-          animation: fadein 1s;
-        }
-
-        nav-exception *, nav-event * {
-          color: #ddd;
-          font-size: 12px;
-        }
-
-        nav-exception > div > a, nav-event > div > a {
-          color: white;
-          text-decoration: none;
-        }
-
-        nav-exception > div > a:hover, nav-event > div > a:hover {
-          text-decoration: underline;
-        }
-
-        nav-exception > div > div {
-          margin-left:20px;
-          white-space: pre
-        }
-
-        nav-exception > div > button, nav-event > div > button {
-          background: transparent;
-          border: none;
-          position: absolute;
-          display: block;
-          top: 4px;
-          right: 4px;
-          height: 18px;
-          width: 18px;
-          line-height: 16px;
-          border-radius: 9px;
-          color: white;
-          font-size: 18px;
-          cursor: pointer;
-          text-align: center;
-        }
-
-        nav-exception > div > button:hover, nav-event > div > button:hover {
-          background: rgba(255,255,255,0.5);
-        }''',
-      new NavNotifyElement(_notifications, notifyOnPause: notifyOnPause,
-                                 queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/refresh.dart b/runtime/observatory/lib/src/elements/nav/refresh.dart
index da40abd..b246851 100644
--- a/runtime/observatory/lib/src/elements/nav/refresh.dart
+++ b/runtime/observatory/lib/src/elements/nav/refresh.dart
@@ -13,7 +13,7 @@
 }
 
 class NavRefreshElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<NavRefreshElement>('nav-refresh-wrapped');
+  static const tag = const Tag<NavRefreshElement>('nav-refresh');
 
   RenderingScheduler _r;
 
@@ -28,7 +28,7 @@
 
   bool get disabled => _disabled;
   String get label => _label;
-  
+
   set disabled(bool value) => _disabled = _r.checkAndReact(_disabled, value);
   set label(String value) => _label = _r.checkAndReact(_label, value);
 
diff --git a/runtime/observatory/lib/src/elements/nav/refresh_wrapper.dart b/runtime/observatory/lib/src/elements/nav/refresh_wrapper.dart
deleted file mode 100644
index 1989a10..0000000
--- a/runtime/observatory/lib/src/elements/nav/refresh_wrapper.dart
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/refresh.dart';
-
-@bindable
-class NavRefreshElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavRefreshElementWrapper>(const {
-      'callback': #callback, 'label': #label
-    });
-
-  static const tag = const Tag<NavRefreshElementWrapper>('nav-refresh');
-
-  Function _callback;
-  String _label;
-  
-  Function get callback => _callback;
-  String get label => _label;
-
-  set callback(Function value) {
-    _callback = value;
-    render();
-  }
-  set label(String value) {
-    _label = value;
-    render();
-  }
-
-  NavRefreshElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _label = getAttribute('label') ?? 'Refresh';
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_callback == null || _label == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''nav-refresh-wrapped > li > button {
-          color: #000;
-          margin: 3px;
-          padding: 8px;
-          border-width: 2px;
-          line-height: 13px;
-          font: 400 13px 'Montserrat', sans-serif;
-        }
-        nav-refresh-wrapped > li > button[disabled] {
-          color: #aaa;
-          cursor: wait;
-        }
-        nav-refresh-wrapped > li {
-          float: right;
-          margin: 0;
-        }''',
-      new NavRefreshElement(label: _label,
-                            queue: ObservatoryApplication.app.queue)
-        ..onRefresh.listen((event) async{
-          event.element.disabled = true;
-          try {
-            var future = callback();
-            if (future is Future) await future;
-          } finally {
-            event.element.disabled = false;
-          }
-        })
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/top_menu.dart b/runtime/observatory/lib/src/elements/nav/top_menu.dart
index f4c6fa1..77a0402 100644
--- a/runtime/observatory/lib/src/elements/nav/top_menu.dart
+++ b/runtime/observatory/lib/src/elements/nav/top_menu.dart
@@ -4,36 +4,36 @@
 
 import 'dart:html';
 import 'dart:async';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/menu_item.dart';
 
 class NavTopMenuElement extends HtmlElement implements Renderable {
   static const tag = const Tag<NavTopMenuElement>('nav-top-menu',
-                     dependencies: const [NavMenuElement.tag,
-                                          NavMenuItemElement.tag]);
+                     dependencies: const [NavMenuItemElement.tag]);
 
   RenderingScheduler _r;
 
   Stream<RenderedEvent<NavTopMenuElement>> get onRendered => _r.onRendered;
 
-  bool _last;
-  
-  bool get last => _last;
+  Iterable<Element> _content = const [];
 
-  set last(bool value) => _last = _r.checkAndReact(_last, value);
+  Iterable<Element> get content => _content;
 
-  factory NavTopMenuElement({bool last: false, RenderingQueue queue}) {
-    assert(last != null);
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
+
+  factory NavTopMenuElement({RenderingQueue queue}) {
     NavTopMenuElement e = document.createElement(tag.name);
     e._r = new RenderingScheduler(e, queue: queue);
-    e._last = last;
     return e;
   }
 
-  NavTopMenuElement.created() : super.created() { createShadowRoot(); }
+  NavTopMenuElement.created() : super.created();
 
   @override
   void attached() {
@@ -45,18 +45,15 @@
   void detached() {
     super.detached();
     _r.disable(notify: true);
-    shadowRoot.children = [];
+    children = [];
   }
 
   void render() {
-    shadowRoot.children = [
-      new NavMenuElement('Observatory', link: Uris.vm(), last: last,
-                         queue: _r.queue)
-        ..children = [
-          new NavMenuItemElement('Connect to a VM', link: Uris.vmConnect(),
-                                 queue: _r.queue),
-          new ContentElement()
-        ]
+    final content = ([
+      new NavMenuItemElement('Connect to a VM', link: Uris.vmConnect()),
+    ]..addAll(_content));
+    children = [
+      navMenu('Observatory', link: Uris.vm(), content: content)
     ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/nav/top_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/top_menu_wrapper.dart
deleted file mode 100644
index db99fff..0000000
--- a/runtime/observatory/lib/src/elements/nav/top_menu_wrapper.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/top_menu.dart';
-
-@bindable
-class NavTopMenuElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavTopMenuElementWrapper>(const {
-      'last': #last
-    });
-
-  static const tag = const Tag<NavTopMenuElementWrapper>('top-nav-menu');
-
-  bool _last = false;
-  
-  bool get last => _last;
-
-  set last(bool value) {
-    _last = value;
-    render();
-  }
-
-  NavTopMenuElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _last = _getBoolAttribute('last');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_last == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavTopMenuElement(last: last, queue: ObservatoryApplication.app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-
-  bool _getBoolAttribute(String name) {
-    final String value = getAttribute(name);
-    return !(value == null || value == 'false');
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/nav/vm_menu.dart b/runtime/observatory/lib/src/elements/nav/vm_menu.dart
index e4351af..c652f36 100644
--- a/runtime/observatory/lib/src/elements/nav/vm_menu.dart
+++ b/runtime/observatory/lib/src/elements/nav/vm_menu.dart
@@ -6,46 +6,45 @@
 import 'dart:async';
 import 'package:observatory/models.dart' as M
   show VM, EventRepository;
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/menu_item.dart';
 
 class NavVMMenuElement extends HtmlElement implements Renderable {
   static const tag = const Tag<NavVMMenuElement>('nav-vm-menu',
-                     dependencies: const [NavMenuElement.tag,
-                                          NavMenuItemElement.tag]);
+                     dependencies: const [NavMenuItemElement.tag]);
 
   RenderingScheduler _r;
 
   Stream<RenderedEvent<NavVMMenuElement>> get onRendered => _r.onRendered;
 
-  bool _last;
   M.VM _vm;
   M.EventRepository _events;
   StreamSubscription _updatesSubscription;
+  Iterable<Element> _content = const [];
 
-
-  bool get last => _last;
   M.VM get vm => _vm;
+  Iterable<Element> get content => _content;
 
-  set last(bool value) => _last = _r.checkAndReact(_last, value);
+  set content(Iterable<Element> value) {
+    _content = value.toList();
+    _r.dirty();
+  }
 
-  factory NavVMMenuElement(M.VM vm, M.EventRepository events, {bool last: false,
-    RenderingQueue queue}) {
+  factory NavVMMenuElement(M.VM vm, M.EventRepository events,
+                           {RenderingQueue queue}) {
     assert(vm != null);
     assert(events != null);
-    assert(last != null);
     NavVMMenuElement e = document.createElement(tag.name);
     e._r = new RenderingScheduler(e, queue: queue);
     e._vm = vm;
     e._events = events;
-    e._last = last;
     return e;
   }
 
-  NavVMMenuElement.created() : super.created() { createShadowRoot(); }
+  NavVMMenuElement.created() : super.created();
 
   @override
   void attached() {
@@ -58,22 +57,21 @@
   @override
   void detached() {
     super.detached();
-    shadowRoot.children = [];
+    children = [];
     _r.disable(notify: true);
     _updatesSubscription.cancel();
   }
 
   void render() {
-    shadowRoot.children = [
-      new NavMenuElement(vm.displayName, link: Uris.vm(), last: last,
-          queue: _r.queue)
-        ..children = (
-          _vm.isolates.map((isolate) {
-            return new NavMenuItemElement(isolate.name, queue: _r.queue,
-                link: Uris.inspect(isolate));
-          }).toList()
-          ..add(new ContentElement())
-        )
+    final content = (
+      _vm.isolates.map((isolate) {
+        return new NavMenuItemElement(isolate.name, queue: _r.queue,
+            link: Uris.inspect(isolate));
+      }).toList()
+      ..addAll(_content)
+    );
+    children = [
+      navMenu(vm.displayName, link: Uris.vm(), content: content)
     ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/nav/vm_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/vm_menu_wrapper.dart
deleted file mode 100644
index ef8bf3d..0000000
--- a/runtime/observatory/lib/src/elements/nav/vm_menu_wrapper.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/service_common.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-import 'package:observatory/src/elements/nav/vm_menu.dart';
-
-@bindable
-class NavVMMenuElementWrapper extends HtmlElement {
-  static const binder = const Binder<NavVMMenuElementWrapper>(const {
-      'last': #last, 'vm': #vm
-    });
-
-  static const tag = const Tag<NavVMMenuElementWrapper>('vm-nav-menu');
-
-  bool _last = false;
-  VM _vm;
-
-  bool get last => _last;
-  VM get vm => _vm;
-
-  set last(bool value) {
-    _last = value;
-    render(); }
-  set vm(VM value) {
-    _vm = value;
-    render();
-  }
-
-  NavVMMenuElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    _last = _getBoolAttribute('last');
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_vm == null || _last == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new NavVMMenuElement(vm, app.events, last: last,
-          queue: app.queue)
-        ..children = [new ContentElement()]
-    ];
-  }
-
-  ObservatoryApplication get app => ObservatoryApplication.app;
-
-  bool _getBoolAttribute(String name) {
-    final String value = getAttribute(name);
-    return !(value == null || value == 'false');
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/object_common.dart b/runtime/observatory/lib/src/elements/object_common.dart
index 3e40ca2..a52dc7b 100644
--- a/runtime/observatory/lib/src/elements/object_common.dart
+++ b/runtime/observatory/lib/src/elements/object_common.dart
@@ -14,7 +14,7 @@
 import 'package:observatory/utils.dart';
 
 class ObjectCommonElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<ObjectCommonElement>('object-common-wrapped',
+  static const tag = const Tag<ObjectCommonElement>('object-common',
       dependencies: const [
         ClassRefElement.tag,
         InboundReferencesElement.tag,
diff --git a/runtime/observatory/lib/src/elements/object_common_wrapper.dart b/runtime/observatory/lib/src/elements/object_common_wrapper.dart
deleted file mode 100644
index 248280b..0000000
--- a/runtime/observatory/lib/src/elements/object_common_wrapper.dart
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/object_common.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class ObjectCommonElementWrapper extends HtmlElement {
-
-  static const binder = const Binder<ObjectCommonElementWrapper>(const {
-      'object': #object
-    });
-
-  static const tag = const Tag<ObjectCommonElementWrapper>('object-common');
-
-  HeapObject _object;
-
-  HeapObject get object => _object;
-
-  void set object(HeapObject value) {
-    _object = value;
-    render();
-  }
-
-  ObjectCommonElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  void render() {
-    shadowRoot.children = [];
-    if (_object == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        object-common-wrapped a[href]:hover {
-            text-decoration: underline;
-        }
-        object-common-wrapped a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }
-        object-common-wrapped .memberList {
-          display: table;
-        }
-        object-common-wrapped .memberItem {
-          display: table-row;
-        }
-        object-common-wrapped .memberName,
-        object-common-wrapped .memberValue {
-          display: table-cell;
-          vertical-align: top;
-          padding: 3px 0 3px 1em;
-          font: 400 14px 'Montserrat', sans-serif;
-        }
-        object-common-wrapped button:hover {
-          background-color: transparent;
-          border: none;
-          text-decoration: underline;
-        }
-
-        object-common-wrapped button {
-          background-color: transparent;
-          border: none;
-          color: #0489c3;
-          padding: 0;
-          margin: -8px 4px;
-          font-size: 20px;
-          text-decoration: none;
-        }
-        object-common-wrapped .indent {
-          margin-left: 1.5em;
-          font: 400 14px 'Montserrat', sans-serif;
-          line-height: 150%;
-        }
-        object-common-wrapped .stackTraceBox {
-          margin-left: 1.5em;
-          background-color: #f5f5f5;
-          border: 1px solid #ccc;
-          padding: 10px;
-          font-family: consolas, courier, monospace;
-          font-size: 12px;
-          white-space: pre;
-          overflow-x: auto;
-        }''',
-      new ObjectCommonElement(_object.isolate, _object,
-                          new RetainedSizeRepository(),
-                          new ReachableSizeRepository(),
-                          new InboundReferencesRepository(),
-                          new RetainingPathRepository(),
-                          new InstanceRepository(),
-                          queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/object_view.dart b/runtime/observatory/lib/src/elements/object_view.dart
index b100d28..89efd2d 100644
--- a/runtime/observatory/lib/src/elements/object_view.dart
+++ b/runtime/observatory/lib/src/elements/object_view.dart
@@ -7,11 +7,11 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/context_ref.dart';
 import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -24,11 +24,9 @@
                                             dependencies: const [
                                               ContextRefElement.tag,
                                               CurlyBlockElement.tag,
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
-                                              NavMenuElement.tag,
                                               NavRefreshElement.tag,
                                               NavNotifyElement.tag,
                                               ObjectCommonElement.tag,
@@ -111,20 +109,19 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('object', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _object = await _objects.get(_isolate, _object.id);
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('object'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _object = await _objects.get(_isolate, _object.id);
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Object',
diff --git a/runtime/observatory/lib/src/elements/objectpool_view.dart b/runtime/observatory/lib/src/elements/objectpool_view.dart
index 9d26998..24ac047 100644
--- a/runtime/observatory/lib/src/elements/objectpool_view.dart
+++ b/runtime/observatory/lib/src/elements/objectpool_view.dart
@@ -10,11 +10,11 @@
 import 'package:observatory/src/elements/context_ref.dart';
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -27,11 +27,9 @@
                                                     dependencies: const [
                                                       ContextRefElement.tag,
                                                       CurlyBlockElement.tag,
-                                                      NavBarElement.tag,
                                                       NavTopMenuElement.tag,
                                                       NavVMMenuElement.tag,
                                                       NavIsolateMenuElement.tag,
-                                                      NavMenuElement.tag,
                                                       NavRefreshElement.tag,
                                                       NavNotifyElement.tag,
                                                       ObjectCommonElement.tag,
@@ -115,20 +113,19 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('instance', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _pool = await _pools.get(_isolate, _pool.id);
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('instance'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _pool = await _pools.get(_isolate, _pool.id);
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Object Pool',
diff --git a/runtime/observatory/lib/src/elements/objectstore_view.dart b/runtime/observatory/lib/src/elements/objectstore_view.dart
index 3939137..d8d5597 100644
--- a/runtime/observatory/lib/src/elements/objectstore_view.dart
+++ b/runtime/observatory/lib/src/elements/objectstore_view.dart
@@ -8,10 +8,10 @@
 import 'dart:html';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
@@ -23,7 +23,6 @@
   static const tag = const Tag<ObjectStoreViewElement>('objectstore-view',
                                             dependencies: const [
                                               InstanceRefElement.tag,
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavIsolateMenuElement.tag,
@@ -91,15 +90,14 @@
   void render() {
     final fields = _store?.fields?.toList(growable: false);
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavRefreshElement(disabled: _store == null, queue: _r.queue)
-              ..onRefresh.listen((e) => _refresh()),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        new NavRefreshElement(disabled: _store == null, queue: _r.queue)
+            ..onRefresh.listen((e) => _refresh()),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h1()
diff --git a/runtime/observatory/lib/src/elements/observatory_element.dart b/runtime/observatory/lib/src/elements/observatory_element.dart
deleted file mode 100644
index ed52cf0..0000000
--- a/runtime/observatory/lib/src/elements/observatory_element.dart
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library observatory_element;
-
-import 'dart:async';
-import 'dart:html';
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-
-/// Base class for all Observatory custom elements.
-class ObservatoryElement extends PolymerElement {
-  ObservatoryElement.created() : super.created();
-
-  ObservatoryApplication get app => ObservatoryApplication.app;
-  Page get page => app.currentPage;
-
-  @override
-  void attached() {
-    super.attached();
-    _startPoll();
-  }
-
-  @override
-  void attributeChanged(String name, var oldValue, var newValue) {
-    super.attributeChanged(name, oldValue, newValue);
-  }
-
-  @override
-  void detached() {
-    super.detached();
-    _stopPoll();
-  }
-
-  @override
-  void ready() {
-    super.ready();
-  }
-
-  /// Set to a non-null value to enable polling on this element. When the poll
-  /// timer fires, onPoll will be called.
-  @observable Duration pollPeriod;
-  Timer _pollTimer;
-
-  /// Called every [pollPeriod] while the element is attached to the DOM.
-  void onPoll() { }
-
-  void pollPeriodChanged(oldValue) {
-    if (pollPeriod != null) {
-      _startPoll();
-    } else {
-      _stopPoll();
-    }
-  }
-
-  void _startPoll() {
-    if (pollPeriod == null) {
-      return;
-    }
-    if (_pollTimer != null) {
-      _pollTimer.cancel();
-    }
-    _pollTimer = new Timer(pollPeriod, _onPoll);
-  }
-
-  void _stopPoll() {
-    if (_pollTimer != null) {
-      _pollTimer.cancel();
-    }
-    _pollTimer = null;
-  }
-
-  void _onPoll() {
-    onPoll();
-    if (pollPeriod == null) {
-      // Stop polling.
-      _stopPoll();
-      return;
-    }
-    // Restart timer.
-    _pollTimer = new Timer(pollPeriod, _onPoll);
-  }
-
-  /// Utility method for handling on-click of <a> tags. Navigates
-  /// within the application using the [LocationManager].
-  void goto(MouseEvent event, var detail, Element target) {
-    app.locationManager.onGoto(event);
-    event.stopPropagation();
-  }
-
-  void onClickGoto(MouseEvent event) {
-    app.locationManager.onGoto(event);
-    event.stopPropagation();
-  }
-
-  String makeLink(String url, [ServiceObject obj]) {
-    if (obj != null) {
-      if (obj is Isolate) {
-        url = '${url}?isolateId=${Uri.encodeComponent(obj.id)}';
-      } else {
-        if (obj.id == null) {
-          // No id
-          return url;
-        }
-        url = ('${url}?isolateId=${Uri.encodeComponent(obj.isolate.id)}'
-                       '&objectId=${Uri.encodeComponent(obj.id)}');
-      }
-    }
-    return url;
-  }
-
-  /// Create a link that can be consumed by [goto].
-  String gotoLink(String url, [ServiceObject obj]) {
-    return app.locationManager.makeLink(makeLink(url, obj));
-  }
-  String gotoLinkForwardingParameters(String url, [ServiceObject obj]) {
-    return app.locationManager.makeLinkForwardingParameters(makeLink(url, obj));
-  }
-
-  String formatTimePrecise(double time) => Utils.formatTimePrecise(time);
-  String formatTimeMilliseconds(int millis) =>
-      Utils.formatTimeMilliseconds(millis);
-  String formatTime(double time) => Utils.formatTime(time);
-
-  String formatSeconds(double x) => Utils.formatSeconds(x);
-
-
-  String formatSize(int bytes) => Utils.formatSize(bytes);
-
-  int parseInt(String value) => int.parse(value);
-
-  String asStringLiteral(String value, [bool wasTruncated=false]) {
-    var result = new List();
-    result.add("'".codeUnitAt(0));
-    for (int codeUnit in value.codeUnits) {
-      if (codeUnit == '\n'.codeUnitAt(0)) result.addAll('\\n'.codeUnits);
-      else if (codeUnit == '\r'.codeUnitAt(0)) result.addAll('\\r'.codeUnits);
-      else if (codeUnit == '\f'.codeUnitAt(0)) result.addAll('\\f'.codeUnits);
-      else if (codeUnit == '\b'.codeUnitAt(0)) result.addAll('\\b'.codeUnits);
-      else if (codeUnit == '\t'.codeUnitAt(0)) result.addAll('\\t'.codeUnits);
-      else if (codeUnit == '\v'.codeUnitAt(0)) result.addAll('\\v'.codeUnits);
-      else if (codeUnit == '\$'.codeUnitAt(0)) result.addAll('\\\$'.codeUnits);
-      else if (codeUnit == '\\'.codeUnitAt(0)) result.addAll('\\\\'.codeUnits);
-      else if (codeUnit == "'".codeUnitAt(0)) result.addAll("'".codeUnits);
-      else if (codeUnit < 32) {
-         var escapeSequence = "\\u" + codeUnit.toRadixString(16).padLeft(4, "0");
-         result.addAll(escapeSequence.codeUnits);
-      } else result.add(codeUnit);
-    }
-    if (wasTruncated) {
-      result.addAll("...".codeUnits);
-    } else {
-      result.add("'".codeUnitAt(0));
-    }
-    return new String.fromCharCodes(result);
-  }
-
-  void clearShadowRoot() {
-    // Remove all non-style elements.
-    // Have to do the following because removeWhere doesn't work on DOM child
-    // node lists. i.e. removeWhere((e) => e is! StyleElement);
-    var styleElements = [];
-    for (var child in shadowRoot.children) {
-      if (child is StyleElement) {
-        styleElements.add(child);
-      }
-    }
-    shadowRoot.children.clear();
-    for (var style in styleElements) {
-      shadowRoot.children.add(style);
-    }
-  }
-
-  void insertTextSpanIntoShadowRoot(String text) {
-    var spanElement = new SpanElement();
-    spanElement.text = text;
-    shadowRoot.children.add(spanElement);
-  }
-
-  void insertLinkIntoShadowRoot(String label, String href, [String title]) {
-    var anchorElement = new AnchorElement();
-    anchorElement.href = href;
-    anchorElement.text = label;
-    if (title != null) {
-      anchorElement.title = title;
-    }
-    anchorElement.onClick.listen(onClickGoto);
-    shadowRoot.children.add(anchorElement);
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/pc_descriptors_ref.dart b/runtime/observatory/lib/src/elements/pc_descriptors_ref.dart
index 9ba1e40..8f724fa 100644
--- a/runtime/observatory/lib/src/elements/pc_descriptors_ref.dart
+++ b/runtime/observatory/lib/src/elements/pc_descriptors_ref.dart
@@ -11,7 +11,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class PcDescriptorsRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<PcDescriptorsRefElement>('pc-ref-wrapped');
+  static const tag = const Tag<PcDescriptorsRefElement>('pc-ref');
 
   RenderingScheduler<PcDescriptorsRefElement> _r;
 
diff --git a/runtime/observatory/lib/src/elements/persistent_handles.dart b/runtime/observatory/lib/src/elements/persistent_handles.dart
index e249ead..f8b56dc 100644
--- a/runtime/observatory/lib/src/elements/persistent_handles.dart
+++ b/runtime/observatory/lib/src/elements/persistent_handles.dart
@@ -9,13 +9,12 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/containers/virtual_collection.dart';
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -38,11 +37,9 @@
          const Tag<PersistentHandlesPageElement>('persistent-handles-page',
                                                  dependencies: const [
                                                    InstanceRefElement.tag,
-                                                   NavBarElement.tag,
                                                    NavTopMenuElement.tag,
                                                    NavVMMenuElement.tag,
                                                    NavIsolateMenuElement.tag,
-                                                   NavMenuElement.tag,
                                                    NavRefreshElement.tag,
                                                    NavNotifyElement.tag,
                                                    VirtualCollectionElement.tag
@@ -110,17 +107,15 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('persistent handles', last: true,
-              link: Uris.persistentHandles(_isolate), queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-            ..onRefresh.listen((_) => _refresh()),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ]
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('persistent handles'),
+        new NavRefreshElement(queue: _r.queue)
+          ..onRefresh.listen((_) => _refresh()),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ])
     ]..addAll(_createHandlers('Persistent Handles',
                               _handles?.elements?.toList(),
                               _createLine,
diff --git a/runtime/observatory/lib/src/elements/ports.dart b/runtime/observatory/lib/src/elements/ports.dart
index 183b686..c71b285 100644
--- a/runtime/observatory/lib/src/elements/ports.dart
+++ b/runtime/observatory/lib/src/elements/ports.dart
@@ -6,13 +6,12 @@
 import 'dart:async';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/helpers/uris.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -22,11 +21,9 @@
 class PortsElement extends HtmlElement implements Renderable {
   static const tag = const Tag<PortsElement>('ports-page',
                                              dependencies: const [
-                                               NavBarElement.tag,
                                                NavTopMenuElement.tag,
                                                NavVMMenuElement.tag,
                                                NavIsolateMenuElement.tag,
-                                               NavMenuElement.tag,
                                                NavRefreshElement.tag,
                                                NavNotifyElement.tag,
                                                InstanceRefElement.tag,
@@ -92,17 +89,15 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('ports', link: Uris.ports(_isolate), last: true,
-                             queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-            ..onRefresh.listen((_) => _refresh()),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('ports'),
+        new NavRefreshElement(queue: _r.queue)
+          ..onRefresh.listen((_) => _refresh()),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()
         ..classes = ['content-centered']
         ..children = [
diff --git a/runtime/observatory/lib/src/elements/retaining_path.dart b/runtime/observatory/lib/src/elements/retaining_path.dart
index 2fb51ad..2fea22c 100644
--- a/runtime/observatory/lib/src/elements/retaining_path.dart
+++ b/runtime/observatory/lib/src/elements/retaining_path.dart
@@ -67,7 +67,7 @@
   void render() {
     children = [
       new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
-        ..children = _createContent()
+        ..content = _createContent()
         ..onToggle.listen((e) async {
           _expanded = e.control.expanded;
           if (_expanded) {
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 7413051..0162ab5 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -16,7 +16,7 @@
 import 'package:observatory/utils.dart';
 
 class ScriptInsetElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<ScriptInsetElement>('script-inset-wrapped');
+  static const tag = const Tag<ScriptInsetElement>('script-inset');
 
   RenderingScheduler _r;
 
@@ -775,7 +775,6 @@
       }
     }
 
-    line.changes.listen((_) => update());
     e.onClick.listen((event) {
       if (busy) {
         return;
diff --git a/runtime/observatory/lib/src/elements/script_inset_wrapper.dart b/runtime/observatory/lib/src/elements/script_inset_wrapper.dart
deleted file mode 100644
index 0dba95a..0000000
--- a/runtime/observatory/lib/src/elements/script_inset_wrapper.dart
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/service_html.dart' show Script;
-import 'package:observatory/src/elements/script_inset.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class ScriptInsetElementWrapper extends HtmlElement {
-  static const binder = const Binder<ScriptInsetElementWrapper>(const {
-      'script': #script, 'startpos': #startPos, 'endpos': #endPos,
-      'currentpos': #currentPos, 'indebuggercontext': #inDebuggerContext,
-      'variables': #variables, 'height': #height
-    });
-
-  static const tag = const Tag<ScriptInsetElementWrapper>('script-inset');
-
-  Script _script;
-  int _startPos;
-  int _endPos;
-  int _currentPos;
-  String _height;
-  bool _inDebuggerContext;
-  Iterable _variables;
-
-  Script get script => _script;
-  int get startPos => _startPos;
-  int get endPos => _endPos;
-  int get currentPos => _currentPos;
-  String get height => _height;
-  bool get inDebuggerContext => _inDebuggerContext;
-  Iterable get variables => _variables;
-
-  set script(Script value) {
-    _script = value;
-    render();
-  }
-  set startPos(int value) {
-    _startPos = value;
-    render();
-  }
-  set endPos(int value) {
-    _endPos = value;
-    render();
-  }
-  set currentPos(int value) {
-    _currentPos = value;
-    render();
-  }
-  set height(String value) {
-    _height = value;
-    render();
-  }
-  set inDebuggerContext(bool value) {
-    _inDebuggerContext = value;
-    render();
-  }
-  set variables(Iterable value) {
-    _variables = value;
-    render();
-  }
-
-  ScriptInsetElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  Future render() async {
-    shadowRoot.children = [];
-    if (_script == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        script-inset-wrapped {
-          position: relative;
-        }
-        script-inset-wrapped button.refresh,
-        script-inset-wrapped button.toggle-profile {
-          background-color: transparent;
-          padding: 0;
-          margin: 0;
-          border: none;
-          position: absolute;
-          display: inline-block;
-          top: 5px;
-          color: #888888;
-          line-height: 30px;
-          font: 400 20px 'Montserrat', sans-serif;
-        }
-        script-inset-wrapped button.refresh {
-          right: 5px;
-          font-size: 25px;
-        }
-        script-inset-wrapped button.toggle-profile {
-          right: 30px;
-          font-size: 20px;
-        }
-        script-inset-wrapped button.toggle-profile.enabled {
-          color: #BB3322;
-        }
-        script-inset-wrapped a {
-          color: #0489c3;
-          text-decoration: none;
-        }
-        script-inset-wrapped a:hover {
-          text-decoration: underline;
-        }
-        script-inset-wrapped .sourceInset {
-        }
-        script-inset-wrapped .sourceTable {
-          position: relative;
-          background-color: #f5f5f5;
-          border: 1px solid #ccc;
-          padding: 10px;
-          width: 100%;
-          box-sizing: border-box;
-          overflow-x: scroll;
-        }
-        script-inset-wrapped .sourceRow {
-          display: flex;
-          flex-direction: row;
-          width: 100%;
-        }
-        script-inset-wrapped .sourceItem,
-        script-inset-wrapped .sourceItemCurrent {
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          line-height: 125%;
-          white-space: pre;
-          max-width: 0;
-        }
-        script-inset-wrapped .currentLine {
-          background-color: #fff;
-        }
-        script-inset-wrapped .currentCol {
-          background-color: #6cf;
-        }
-        script-inset-wrapped .hitsCurrent,
-        script-inset-wrapped .hitsNone,
-        script-inset-wrapped .hitsNotExecuted,
-        script-inset-wrapped .hitsExecuted,
-        script-inset-wrapped .hitsCompiled,
-        script-inset-wrapped .hitsNotCompiled {
-          display: table-cell;
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          margin-left: 5px;
-          margin-right: 5px;
-          text-align: right;
-          color: #a8a8a8;
-        }
-        script-inset-wrapped .hitsCurrent {
-          background-color: #6cf;
-          color: black;
-        }
-        script-inset-wrapped .hitsNotExecuted {
-          background-color: #faa;
-        }
-        script-inset-wrapped .hitsExecuted {
-          background-color: #aea;
-        }
-        script-inset-wrapped .hitsCompiled {
-          background-color: #e0e0e0;
-        }
-        script-inset-wrapped .hitsNotCompiled {
-          background-color: #f0c5c5;
-        }
-        script-inset-wrapped .noCopy {}
-        script-inset-wrapped .emptyBreakpoint,
-        script-inset-wrapped .possibleBreakpoint,
-        script-inset-wrapped .busyBreakpoint,
-        script-inset-wrapped .unresolvedBreakpoint,
-        script-inset-wrapped .resolvedBreakpoint  {
-          display: table-cell;
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          width: 1em;
-          text-align: center;
-          cursor: pointer;
-        }
-        script-inset-wrapped .possibleBreakpoint {
-          color: #e0e0e0;
-        }
-        script-inset-wrapped .possibleBreakpoint:hover {
-          color: white;
-          background-color: #777;
-        }
-        script-inset-wrapped .busyBreakpoint {
-          color: white;
-          background-color: black;
-          cursor: wait;
-        }
-        script-inset-wrapped .unresolvedBreakpoint {
-          color: white;
-          background-color: #cac;
-        }
-        script-inset-wrapped .resolvedBreakpoint {
-          color: white;
-          background-color: #e66;
-        }
-        script-inset-wrapped .unresolvedBreakAnnotation {
-          color: white;
-          background-color: #cac;
-        }
-        script-inset-wrapped .resolvedBreakAnnotation {
-          color: white;
-          background-color: #e66;
-        }
-        script-inset-wrapped .notSourceProfile,
-        script-inset-wrapped .noProfile,
-        script-inset-wrapped .coldProfile,
-        script-inset-wrapped .mediumProfile,
-        script-inset-wrapped .hotProfile {
-          display: table-cell;
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          width: 4em;
-          text-align: right;
-          cursor: pointer;
-          margin-left: 5px;
-          margin-right: 5px;
-        }
-        script-inset-wrapped .notSourceProfile {
-        }
-        script-inset-wrapped .noProfile {
-          background-color: #e0e0e0;
-        }
-        script-inset-wrapped .coldProfile {
-          background-color: #aea;
-        }
-        script-inset-wrapped .mediumProfile {
-          background-color: #fe9;
-        }
-        script-inset-wrapped .hotProfile {
-          background-color: #faa;
-        }''',
-      new ScriptInsetElement(_script.isolate, _script,
-                             new ScriptRepository(),
-                             new InstanceRepository(),
-                             ObservatoryApplication.app.events,
-                             startPos: _startPos,
-                             endPos: _endPos,
-                             currentPos: _currentPos,
-                             inDebuggerContext: _inDebuggerContext ?? false,
-                             variables: _variables ?? const [],
-                             queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/script_ref.dart b/runtime/observatory/lib/src/elements/script_ref.dart
index 67ae388..b9b3ddb 100644
--- a/runtime/observatory/lib/src/elements/script_ref.dart
+++ b/runtime/observatory/lib/src/elements/script_ref.dart
@@ -12,7 +12,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class ScriptRefElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<ScriptRefElement>('script-ref-wrapped');
+  static const tag = const Tag<ScriptRefElement>('script-ref');
 
   RenderingScheduler _r;
 
diff --git a/runtime/observatory/lib/src/elements/script_ref_wrapper.dart b/runtime/observatory/lib/src/elements/script_ref_wrapper.dart
deleted file mode 100644
index 8f0e343..0000000
--- a/runtime/observatory/lib/src/elements/script_ref_wrapper.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/service_html.dart' show Script;
-import 'package:observatory/src/elements/script_ref.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class ScriptRefElementWrapper extends HtmlElement {
-  static const binder = const Binder<ScriptRefElementWrapper>(const {
-      'ref': #ref
-    });
-
-  static const tag = const Tag<ScriptRefElementWrapper>('script-ref');
-
-  Script _script;
-
-  Script get ref => _script;
-
-  set ref(Script value) {
-    _script = value;
-    render();
-  }
-
-  ScriptRefElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  Future render() async {
-    shadowRoot.children = [];
-    if (_script == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        script-ref-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        script-ref-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new ScriptRefElement(_script.isolate, _script,
-                                 queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/script_view.dart b/runtime/observatory/lib/src/elements/script_view.dart
index 0aa87d2..98f0731 100644
--- a/runtime/observatory/lib/src/elements/script_view.dart
+++ b/runtime/observatory/lib/src/elements/script_view.dart
@@ -9,12 +9,12 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/context_ref.dart';
 import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import 'package:observatory/src/elements/nav/library_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -28,12 +28,10 @@
                                                   dependencies: const [
                                                     ContextRefElement.tag,
                                                     CurlyBlockElement.tag,
-                                                    NavBarElement.tag,
                                                     NavTopMenuElement.tag,
                                                     NavVMMenuElement.tag,
                                                     NavIsolateMenuElement.tag,
                                                     NavLibraryMenuElement.tag,
-                                                    NavMenuElement.tag,
                                                     NavRefreshElement.tag,
                                                     NavNotifyElement.tag,
                                                     ObjectCommonElement.tag,
@@ -121,21 +119,20 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavLibraryMenuElement(_isolate, _script.library, queue: _r.queue),
-          new NavMenuElement('object', last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _script = await _scripts.get(_isolate, _script.id);
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        new NavLibraryMenuElement(_isolate, _script.library, queue: _r.queue),
+        navMenu('object'),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _script = await _scripts.get(_isolate, _script.id);
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()..text = 'Script',
diff --git a/runtime/observatory/lib/src/elements/sentinel_view.dart b/runtime/observatory/lib/src/elements/sentinel_view.dart
index 8fff0d5..eb8cd90 100644
--- a/runtime/observatory/lib/src/elements/sentinel_view.dart
+++ b/runtime/observatory/lib/src/elements/sentinel_view.dart
@@ -5,11 +5,11 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/nav_menu.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/nav/vm_menu.dart';
@@ -19,11 +19,9 @@
 class SentinelViewElement extends HtmlElement implements Renderable {
   static const tag = const Tag<SentinelViewElement>('sentinel-view',
                                                     dependencies: const [
-                                                      NavBarElement.tag,
                                                       NavTopMenuElement.tag,
                                                       NavVMMenuElement.tag,
                                                       NavIsolateMenuElement.tag,
-                                                      NavMenuElement.tag,
                                                       NavNotifyElement.tag,
                                                       ViewFooterElement.tag
                                                     ]);
@@ -77,14 +75,13 @@
 
   void render() {
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, queue: _r.queue),
-          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
-          new NavMenuElement('sentinel', last: true, queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+        navMenu('sentinel'),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h2()
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
deleted file mode 100644
index 1c48f86..0000000
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library service_ref_element;
-
-import 'dart:html';
-
-import 'package:logging/logging.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/repositories.dart';
-import 'package:polymer/polymer.dart';
-
-import 'helpers/any_ref.dart';
-import 'observatory_element.dart';
-
-class ServiceRefElement extends ObservatoryElement {
-  @published ServiceObject ref;
-  @published bool internal = false;
-  @published String expandKey;
-  ServiceRefElement.created() : super.created();
-
-  void refChanged(oldValue) {
-    notifyPropertyChange(#url, "", url);
-    notifyPropertyChange(#name, [], name);
-    notifyPropertyChange(#nameIsEmpty, 0, 1);
-    notifyPropertyChange(#hoverText, "", hoverText);
-  }
-
-  String get url {
-    if (ref == null) {
-      return 'NULL REF';
-    }
-    return gotoLink('/inspect', ref);
-  }
-
-  String get serviceId {
-    if (ref == null) {
-      return 'NULL REF';
-    }
-    return ref.id;
-  }
-
-  String get hoverText {
-    if (ref == null) {
-      return 'NULL REF';
-    }
-    return ref.vmName;
-  }
-
-  String get name {
-    if (ref == null) {
-      return 'NULL REF';
-    }
-    return ref.name;
-  }
-
-  // Workaround isEmpty not being useable due to missing @MirrorsUsed.
-  bool get nameIsEmpty {
-    return (name == null) || name.isEmpty;
-  }
-
-
-  @published bool expanded = false;
-  dynamic expander() {
-    return expandEvent;
-  }
-  void expandEvent(bool expand, Function onDone) {
-    if (expand) {
-      ref.reload().then((result) {
-        ref = result;
-        notifyPropertyChange(#ref, 0, 1);
-        expanded = true;
-      }).whenComplete(onDone);
-    } else {
-      expanded = false;
-      onDone();
-    }
-  }
-}
-
-
-@CustomTag('any-service-ref')
-class AnyServiceRefElement extends ObservatoryElement {
-  @published ServiceObject ref;
-  @published String expandKey;
-  @published bool asValue = false;
-  AnyServiceRefElement.created() : super.created();
-
-  refChanged(oldValue) {
-    // Remove the current view.
-    children.clear();
-    if (ref == null) {
-      Logger.root.info('Viewing null object.');
-      return;
-    }
-    var obj;
-    if (ref is Guarded) {
-      var g = ref as Guarded;
-      obj = g.asValue ?? g.asSentinel;
-    } else {
-      obj = ref;
-    }
-    var element;
-    switch (obj.type) {
-      case 'Class':
-        if (asValue) {
-          element = new Element.tag('class-ref-as-value');
-          element.ref = obj;
-        } else {
-          element = new Element.tag('class-ref');
-          element.ref = obj;
-        }
-        break;
-      case 'Code':
-        element = new Element.tag('code-ref');
-        element.ref = obj;
-        break;
-      case 'Context':
-        element = new Element.tag('context-ref');
-        element.ref = obj;
-        break;
-      case 'Error':
-        element = new Element.tag('error-ref');
-        element.ref = obj;
-        break;
-      case 'Field':
-        element = new Element.tag('field-ref');
-        element.ref = obj;
-        break;
-      case 'Function':
-        element = new Element.tag('function-ref');
-        element.ref = obj;
-        break;
-      case 'Instance':
-        element = new Element.tag('instance-ref');
-        element.ref = obj;
-        break;
-      case 'Library':
-        if (asValue) {
-          element =
-              new Element.tag('library-ref-as-value');
-          element.ref = obj;
-        } else {
-          element =
-              new Element.tag('library-ref');
-          element.ref = obj;
-        }
-        break;
-      case 'Script':
-        element = new Element.tag('script-ref');
-        element.ref = obj;
-        break;
-      default:
-        element = anyRef(obj.isolate, obj,
-            new InstanceRepository(), queue: app.queue);
-        break;
-    }
-    if (element == null) {
-      Logger.root.info('Unable to find a ref element for \'${ref.type}\'');
-      element = new Element.tag('span');
-      element.text = "<<Unknown service ref: $ref>>";
-      return;
-    }
-    children.add(element);
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/service_ref.html b/runtime/observatory/lib/src/elements/service_ref.html
deleted file mode 100644
index d401cc8..0000000
--- a/runtime/observatory/lib/src/elements/service_ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="any-service-ref">
-</polymer-element>
-
-<script type="application/dart" src="service_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/shims/binding.dart b/runtime/observatory/lib/src/elements/shims/binding.dart
deleted file mode 100644
index c5425c4..0000000
--- a/runtime/observatory/lib/src/elements/shims/binding.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2016, 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:core';
-import 'dart:html';
-import 'dart:js';
-@MirrorsUsed(metaTargets: const [BindableAnnotation])
-import 'dart:mirrors';
-import 'package:js/js.dart';
-import 'package:js_util/js_util.dart';
-import 'package:polymer/polymer.dart';
-
-const BindableAnnotation bindable = const BindableAnnotation();
-class BindableAnnotation {
-  const BindableAnnotation();
-}
-
-
-///This is a temporary bridge between Polymer Bindings and the wrapper entities.
-class Binder<T extends HtmlElement> {
-  final Map<String, Symbol> attributes;
-
-  const Binder(Map<String, Symbol> attributes)
-      : attributes = attributes;
-
-  registerCallback(T element) {
-    assert(element != null);
-    setValue(element, 'bind', allowInteropCaptureThis(_callback));
-  }
-
-  void _callback(_this, name, value, [other]) {
-    final setter = attributes[name];
-    if (setter == null) return;
-    Bindable bindable;
-    if (identical(1, 1.0)) { // dart2js
-      bindable = getValue(getValue(value, '__dartBindable'), 'o') as Bindable;
-    } else { // vm
-      bindable = getValue(value, '__dartBindable');
-    }
-    var obj = reflect(_this);
-    obj.setField(setter, bindable.value);
-    bindable.open((value) {
-      obj.setField(setter, value);
-    });
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/source_inset.dart b/runtime/observatory/lib/src/elements/source_inset.dart
index b62376a..69be9b3 100644
--- a/runtime/observatory/lib/src/elements/source_inset.dart
+++ b/runtime/observatory/lib/src/elements/source_inset.dart
@@ -12,7 +12,7 @@
 import 'package:observatory/src/elements/script_inset.dart';
 
 class SourceInsetElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<SourceInsetElement>('source-inset-wrapped');
+  static const tag = const Tag<SourceInsetElement>('source-inset');
 
   RenderingScheduler _r;
 
diff --git a/runtime/observatory/lib/src/elements/source_inset_wrapper.dart b/runtime/observatory/lib/src/elements/source_inset_wrapper.dart
deleted file mode 100644
index 26c2ba8..0000000
--- a/runtime/observatory/lib/src/elements/source_inset_wrapper.dart
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart';
-import 'package:observatory/service_html.dart' show SourceLocation;
-import 'package:observatory/src/elements/script_inset.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class SourceInsetElementWrapper extends HtmlElement {
-  static const binder = const Binder<SourceInsetElementWrapper>(const {
-      'location': #location, 'currentpos': #currentPos,
-      'indebuggercontext': #inDebuggerContext, 'variables': #variables
-    });
-
-  static const tag = const Tag<SourceInsetElementWrapper>('source-inset');
-
-  SourceLocation _location;
-  int _currentPos;
-  bool _inDebuggerContext;
-  Iterable _variables;
-
-  SourceLocation get location => _location;
-  int get currentPos => _currentPos;
-  bool get inDebuggerContext => _inDebuggerContext;
-  Iterable get variables => _variables;
-
-  set location(SourceLocation value) {
-    _location = value;
-    render();
-  }
-  set currentPos(int value) {
-    _currentPos = value;
-    render();
-  }
-  set inDebuggerContext(bool value) {
-    _inDebuggerContext = value;
-    render();
-  }
-  set variables(Iterable value) {
-    _variables = value;
-    render();
-  }
-
-  SourceInsetElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  Future render() async {
-    shadowRoot.children = [];
-    if (_location == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        script-inset-wrapped {
-          position: relative;
-        }
-        script-inset-wrapped button.refresh,
-        script-inset-wrapped button.toggle-profile {
-          background-color: transparent;
-          padding: 0;
-          margin: 0;
-          border: none;
-          position: absolute;
-          display: inline-block;
-          top: 5px;
-          color: #888888;
-          line-height: 30px;
-          font: 400 20px 'Montserrat', sans-serif;
-        }
-        script-inset-wrapped button.refresh {
-          right: 5px;
-          font-size: 25px;
-        }
-        script-inset-wrapped button.toggle-profile {
-          right: 30px;
-          font-size: 20px;
-        }
-        script-inset-wrapped button.toggle-profile.enabled {
-          color: #BB3322;
-        }
-        script-inset-wrapped a {
-          color: #0489c3;
-          text-decoration: none;
-        }
-        script-inset-wrapped a:hover {
-          text-decoration: underline;
-        }
-        script-inset-wrapped .sourceInset {
-        }
-        script-inset-wrapped .sourceTable {
-          position: relative;
-          background-color: #f5f5f5;
-          border: 1px solid #ccc;
-          padding: 10px;
-          width: 100%;
-          box-sizing: border-box;
-          overflow-x: scroll;
-        }
-        script-inset-wrapped .sourceRow {
-          display: flex;
-          flex-direction: row;
-          width: 100%;
-        }
-        script-inset-wrapped .sourceItem,
-        script-inset-wrapped .sourceItemCurrent {
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          line-height: 125%;
-          white-space: pre;
-          max-width: 0;
-        }
-        script-inset-wrapped .currentLine {
-          background-color: #fff;
-        }
-        script-inset-wrapped .currentCol {
-          background-color: #6cf;
-        }
-        script-inset-wrapped .hitsCurrent,
-        script-inset-wrapped .hitsNone,
-        script-inset-wrapped .hitsNotExecuted,
-        script-inset-wrapped .hitsExecuted,
-        script-inset-wrapped .hitsCompiled,
-        script-inset-wrapped .hitsNotCompiled {
-          display: table-cell;
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          margin-left: 5px;
-          margin-right: 5px;
-          text-align: right;
-          color: #a8a8a8;
-        }
-        script-inset-wrapped .hitsCurrent {
-          background-color: #6cf;
-          color: black;
-        }
-        script-inset-wrapped .hitsNotExecuted {
-          background-color: #faa;
-        }
-        script-inset-wrapped .hitsExecuted {
-          background-color: #aea;
-        }
-        script-inset-wrapped .hitsCompiled {
-          background-color: #e0e0e0;
-        }
-        script-inset-wrapped .hitsNotCompiled {
-          background-color: #f0c5c5;
-        }
-        script-inset-wrapped .noCopy {}
-        script-inset-wrapped .emptyBreakpoint,
-        script-inset-wrapped .possibleBreakpoint,
-        script-inset-wrapped .busyBreakpoint,
-        script-inset-wrapped .unresolvedBreakpoint,
-        script-inset-wrapped .resolvedBreakpoint  {
-          display: table-cell;
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          width: 1em;
-          text-align: center;
-          cursor: pointer;
-        }
-        script-inset-wrapped .possibleBreakpoint {
-          color: #e0e0e0;
-        }
-        script-inset-wrapped .possibleBreakpoint:hover {
-          color: white;
-          background-color: #777;
-        }
-        script-inset-wrapped .busyBreakpoint {
-          color: white;
-          background-color: black;
-          cursor: wait;
-        }
-        script-inset-wrapped .unresolvedBreakpoint {
-          color: white;
-          background-color: #cac;
-        }
-        script-inset-wrapped .resolvedBreakpoint {
-          color: white;
-          background-color: #e66;
-        }
-        script-inset-wrapped .unresolvedBreakAnnotation {
-          color: white;
-          background-color: #cac;
-        }
-        script-inset-wrapped .resolvedBreakAnnotation {
-          color: white;
-          background-color: #e66;
-        }
-        script-inset-wrapped .notSourceProfile,
-        script-inset-wrapped .noProfile,
-        script-inset-wrapped .coldProfile,
-        script-inset-wrapped .mediumProfile,
-        script-inset-wrapped .hotProfile {
-          display: table-cell;
-          vertical-align: top;
-          font: 400 14px consolas, courier, monospace;
-          width: 4em;
-          text-align: right;
-          cursor: pointer;
-          margin-left: 5px;
-          margin-right: 5px;
-        }
-        script-inset-wrapped .notSourceProfile {
-        }
-        script-inset-wrapped .noProfile {
-          background-color: #e0e0e0;
-        }
-        script-inset-wrapped .coldProfile {
-          background-color: #aea;
-        }
-        script-inset-wrapped .mediumProfile {
-          background-color: #fe9;
-        }
-        script-inset-wrapped .hotProfile {
-          background-color: #faa;
-        }''',
-      new ScriptInsetElement(_location.script.isolate, _location.script,
-                             new ScriptRepository(),
-                             new InstanceRepository(),
-                             ObservatoryApplication.app.events,
-                             startPos: _location.tokenPos,
-                             endPos: _location.endTokenPos,
-                             currentPos: _currentPos,
-                             inDebuggerContext: _inDebuggerContext ?? false,
-                             variables: _variables ?? const [],
-                             queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/source_link.dart b/runtime/observatory/lib/src/elements/source_link.dart
index ca65709..77ef2fe 100644
--- a/runtime/observatory/lib/src/elements/source_link.dart
+++ b/runtime/observatory/lib/src/elements/source_link.dart
@@ -13,7 +13,7 @@
 import 'package:observatory/src/elements/helpers/uris.dart';
 
 class SourceLinkElement extends HtmlElement implements Renderable {
-  static const tag = const Tag<SourceLinkElement>('source-link-wrapped');
+  static const tag = const Tag<SourceLinkElement>('source-link');
 
   RenderingScheduler _r;
 
diff --git a/runtime/observatory/lib/src/elements/source_link_wrapper.dart b/runtime/observatory/lib/src/elements/source_link_wrapper.dart
deleted file mode 100644
index 199f949..0000000
--- a/runtime/observatory/lib/src/elements/source_link_wrapper.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'dart:async';
-
-import 'package:observatory/app.dart';
-import 'package:observatory/repositories.dart' show ScriptRepository;
-import 'package:observatory/service_html.dart' show SourceLocation;
-import 'package:observatory/src/elements/source_link.dart';
-import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/shims/binding.dart';
-
-@bindable
-class SourceLinkElementWrapper extends HtmlElement {
-  static const binder = const Binder<SourceLinkElementWrapper>(const {
-      'location' : #location
-    });
-
-  static const tag = const Tag<SourceLinkElementWrapper>('source-link');
-
-  SourceLocation _location;
-  SourceLocation get location => location;
-  set location(SourceLocation value) {
-    _location = value;
-    render();
-  }
-
-  SourceLinkElementWrapper.created() : super.created() {
-    binder.registerCallback(this);
-    createShadowRoot();
-    render();
-  }
-
-  @override
-  void attached() {
-    super.attached();
-    render();
-  }
-
-  Future render() async {
-    shadowRoot.children = [];
-    if (_location == null) {
-      return;
-    }
-
-    shadowRoot.children = [
-      new StyleElement()
-        ..text = '''
-        source-link-wrapped > a[href]:hover {
-            text-decoration: underline;
-        }
-        source-link-wrapped > a[href] {
-            color: #0489c3;
-            text-decoration: none;
-        }''',
-      new SourceLinkElement(_location.isolate, _location,
-                            new ScriptRepository(),
-                            queue: ObservatoryApplication.app.queue)
-    ];
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/strongly_reachable_instances.dart b/runtime/observatory/lib/src/elements/strongly_reachable_instances.dart
index f7538e8..c4b85ad 100644
--- a/runtime/observatory/lib/src/elements/strongly_reachable_instances.dart
+++ b/runtime/observatory/lib/src/elements/strongly_reachable_instances.dart
@@ -71,7 +71,7 @@
   void render() {
     children = [
       new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
-        ..children = _createContent()
+        ..content = _createContent()
         ..onToggle.listen((e) async {
           _expanded = e.control.expanded;
           e.control.disabled = true;
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index 8e7b3ef..373ed44 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -10,9 +10,9 @@
 import 'package:observatory/service.dart' as S;
 import 'package:observatory/service_html.dart' as SH;
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -29,7 +29,6 @@
 class TimelinePageElement extends HtmlElement implements Renderable {
   static const tag = const Tag<TimelinePageElement>('timeline-page',
                                                     dependencies: const [
-                                                      NavBarElement.tag,
                                                       NavTopMenuElement.tag,
                                                       NavVMMenuElement.tag,
                                                       NavRefreshElement.tag,
@@ -121,36 +120,35 @@
     ];
     if (children.isEmpty) {
       children = [
-        new NavBarElement(queue: _r.queue)
-          ..children = [
-            new NavTopMenuElement(queue: _r.queue),
-            new NavVMMenuElement(_vm, _events, last: true, queue: _r.queue),
-            new NavRefreshElement(queue: _r.queue)
-                ..onRefresh.listen((e) async {
-                  e.element.disabled = true;
-                  await _refresh();
-                  e.element.disabled = false;
-                }),
-            new NavRefreshElement(label: 'clear', queue: _r.queue)
-                ..onRefresh.listen((e) async {
-                  e.element.disabled = true;
-                  await _clear();
-                  e.element.disabled = false;
-                }),
-            new NavRefreshElement(label: 'save', queue: _r.queue)
-                ..onRefresh.listen((e) async {
-                  e.element.disabled = true;
-                  await _save();
-                  e.element.disabled = false;
-                }),
-            new NavRefreshElement(label: 'load', queue: _r.queue)
-                ..onRefresh.listen((e) async {
-                  e.element.disabled = true;
-                  await _load();
-                  e.element.disabled = false;
-                }),
-            new NavNotifyElement(_notifications, queue: _r.queue)
-          ],
+        navBar([
+          new NavTopMenuElement(queue: _r.queue),
+          new NavVMMenuElement(_vm, _events, queue: _r.queue),
+          new NavRefreshElement(queue: _r.queue)
+              ..onRefresh.listen((e) async {
+                e.element.disabled = true;
+                await _refresh();
+                e.element.disabled = false;
+              }),
+          new NavRefreshElement(label: 'clear', queue: _r.queue)
+              ..onRefresh.listen((e) async {
+                e.element.disabled = true;
+                await _clear();
+                e.element.disabled = false;
+              }),
+          new NavRefreshElement(label: 'save', queue: _r.queue)
+              ..onRefresh.listen((e) async {
+                e.element.disabled = true;
+                await _save();
+                e.element.disabled = false;
+              }),
+          new NavRefreshElement(label: 'load', queue: _r.queue)
+              ..onRefresh.listen((e) async {
+                e.element.disabled = true;
+                await _load();
+                e.element.disabled = false;
+              }),
+          new NavNotifyElement(_notifications, queue: _r.queue)
+        ]),
         _content,
         new DivElement()..classes = ['iframe']
           ..children = [
diff --git a/runtime/observatory/lib/src/elements/top_retaining_instances.dart b/runtime/observatory/lib/src/elements/top_retaining_instances.dart
index a3c6fe2..3f72d3b 100644
--- a/runtime/observatory/lib/src/elements/top_retaining_instances.dart
+++ b/runtime/observatory/lib/src/elements/top_retaining_instances.dart
@@ -70,7 +70,7 @@
   void render() {
     children = [
       new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
-        ..children = [
+        ..content = [
           new DivElement()..classes = ['memberList']
             ..children = _createContent()
         ]
diff --git a/runtime/observatory/lib/src/elements/view_footer.dart b/runtime/observatory/lib/src/elements/view_footer.dart
index 3e7dcd1..8498090 100644
--- a/runtime/observatory/lib/src/elements/view_footer.dart
+++ b/runtime/observatory/lib/src/elements/view_footer.dart
@@ -22,10 +22,7 @@
     return e;
   }
 
-  ViewFooterElement.created() : super.created() {
-    // TODO(cbernaschina) remove this when polymer is removed.
-    _r = new RenderingScheduler(this);
-  }
+  ViewFooterElement.created() : super.created();
 
   @override
   void attached() {
diff --git a/runtime/observatory/lib/src/elements/vm_connect.dart b/runtime/observatory/lib/src/elements/vm_connect.dart
index a322e91..3f20e26 100644
--- a/runtime/observatory/lib/src/elements/vm_connect.dart
+++ b/runtime/observatory/lib/src/elements/vm_connect.dart
@@ -10,7 +10,7 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/view_footer.dart';
@@ -20,8 +20,7 @@
 
 class VMConnectElement extends HtmlElement implements Renderable {
   static const tag = const Tag<VMConnectElement>('vm-connect',
-                     dependencies: const [NavBarElement.tag,
-                                          NavTopMenuElement.tag,
+                     dependencies: const [NavTopMenuElement.tag,
                                           NavNotifyElement.tag,
                                           ViewFooterElement.tag,
                                           VMConnectTargetElement.tag]);
@@ -75,11 +74,10 @@
     final host = window.location.hostname;
     final port = window.location.port;
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(last: true, queue: _r.queue),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()
         ..classes = ['content-centered']
         ..children = [
diff --git a/runtime/observatory/lib/src/elements/vm_view.dart b/runtime/observatory/lib/src/elements/vm_view.dart
index f037f78..d5ff9a4 100644
--- a/runtime/observatory/lib/src/elements/vm_view.dart
+++ b/runtime/observatory/lib/src/elements/vm_view.dart
@@ -7,11 +7,11 @@
 import 'dart:async';
 import 'dart:html';
 import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/nav_bar.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/uris.dart';
 import 'package:observatory/src/elements/isolate/summary.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
@@ -22,7 +22,6 @@
   static const tag = const Tag<VMViewElement>('vm-view',
                                             dependencies: const [
                                               IsolateSummaryElement.tag,
-                                              NavBarElement.tag,
                                               NavTopMenuElement.tag,
                                               NavVMMenuElement.tag,
                                               NavRefreshElement.tag,
@@ -92,17 +91,16 @@
     final uptime = new DateTime.now().difference(_vm.startTime);
     final isolates = _vm.isolates.toList();
     children = [
-      new NavBarElement(queue: _r.queue)
-        ..children = [
-          new NavTopMenuElement(queue: _r.queue),
-          new NavVMMenuElement(_vm, _events, last: true, queue: _r.queue),
-          new NavRefreshElement(queue: _r.queue)
-              ..onRefresh.listen((e) async {
-                e.element.disabled = true;
-                _r.dirty();
-              }),
-          new NavNotifyElement(_notifications, queue: _r.queue)
-        ],
+      navBar([
+        new NavTopMenuElement(queue: _r.queue),
+        new NavVMMenuElement(_vm, _events, queue: _r.queue),
+        new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((e) async {
+              e.element.disabled = true;
+              _r.dirty();
+            }),
+        new NavNotifyElement(_notifications, queue: _r.queue)
+      ]),
       new DivElement()..classes = ['content-centered-big']
         ..children = [
           new HeadingElement.h1()..text = 'VM',
diff --git a/runtime/observatory/lib/src/models/objects/metric.dart b/runtime/observatory/lib/src/models/objects/metric.dart
new file mode 100644
index 0000000..fd8f7ac
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/metric.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of models;
+
+abstract class Metric {
+  String get id;
+  String get name;
+  String get description;
+}
+
+abstract class MetricSample {
+  double get value;
+  DateTime get time;
+}
diff --git a/runtime/observatory/lib/src/models/repositories/metric.dart b/runtime/observatory/lib/src/models/repositories/metric.dart
new file mode 100644
index 0000000..a009fe1
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/metric.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+enum MetricBufferSize {
+  n10samples,
+  n100samples,
+  n1000samples
+}
+
+enum MetricSamplingRate {
+  off,
+  e100ms,
+  e1s,
+  e2s,
+  e4s,
+  e8s
+}
+
+abstract class MetricRepository {
+  Future<Iterable<Metric>> list(IsolateRef isolate);
+  void setSamplingRate(IsolateRef isolate, Metric metric, MetricSamplingRate r);
+  MetricSamplingRate getSamplingRate(IsolateRef isolate, Metric metric);
+  void setBufferSize(IsolateRef isolate, Metric metric, MetricBufferSize r);
+  MetricBufferSize getBufferSize(IsolateRef isolate, Metric metric);
+  Iterable<MetricSample> getSamples(IsolateRef isolate, Metric metric);
+  double getMinValue(IsolateRef isolate, Metric metric);
+  double getMaxValue(IsolateRef isolate, Metric metric);
+}
diff --git a/runtime/observatory/lib/src/repositories/metric.dart b/runtime/observatory/lib/src/repositories/metric.dart
new file mode 100644
index 0000000..5e81b75
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/metric.dart
@@ -0,0 +1,192 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class Metric implements M.Metric {
+  final String id;
+  String get name => internal.name;
+  String get description => internal.description;
+  final internal;
+
+  Metric(this.id, this.internal);
+}
+
+class MetricSample implements M.MetricSample {
+  final double value;
+  final DateTime time = new DateTime.now();
+  MetricSample(this.value);
+}
+
+class MetricRepository implements M.MetricRepository {
+  final Map<S.Isolate, Map<Metric, List<M.MetricSample>>> _samples
+    = <S.Isolate, Map<Metric, List<M.MetricSample>>>{};
+  final Map<S.Isolate, Map<Metric, int>> _rates
+    = <S.Isolate, Map<Metric, int>>{};
+  final Map<S.Isolate, Map<Metric, int>> _sizes
+    = <S.Isolate, Map<Metric, int>>{};
+  Timer _timer;
+  int count = 0;
+
+  Future<Iterable<Metric>> list(M.IsolateRef i) async{
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    if (_samples.containsKey(isolate)) {
+      return _samples[isolate].keys;
+    }
+    return const [];
+  }
+
+  Future startSampling(M.IsolateRef i) async {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    if (!_samples.containsKey(isolate)) {
+      await isolate.refreshMetrics();
+      final samples = _samples[isolate] = <Metric, List<M.MetricSample>>{};
+      final rates = _rates[isolate] = <Metric, int>{};
+      final sizes = _sizes[isolate] = <Metric, int>{};
+      final metrics = []
+        ..addAll(isolate.dartMetrics.keys.map((name) =>
+            new Metric(name, isolate.dartMetrics[name])).toList())
+        ..addAll(isolate.nativeMetrics.keys.map((name) =>
+            new Metric(name, isolate.nativeMetrics[name])).toList());
+      for (final metric in metrics) {
+        samples[metric] = [new MetricSample(metric.internal.value)];
+        rates[metric] = _rateToInteger(M.MetricSamplingRate.off);
+        sizes[metric] = _sizeToInteger(M.MetricBufferSize.n100samples);
+      }
+      if (_samples.length == 1) {
+        count = 0;
+        _timer = new Timer.periodic(new Duration(milliseconds: 100), _update);
+      }
+    }
+  }
+
+  Future stopSampling(M.IsolateRef isolate) async {
+    if (_samples.containsKey(isolate)) {
+      _samples.remove(isolate);
+      _rates.remove(isolate);
+      _sizes.remove(isolate);
+      if (_samples.isEmpty) {
+        _timer.cancel();
+      }
+    }
+  }
+
+  M.MetricSamplingRate getSamplingRate(M.IsolateRef i, M.Metric m) {
+    if (_rates.containsKey(i)) {
+      final metrics = _rates[i];
+      if (metrics.containsKey(m)) {
+        switch (metrics[m]) {
+          case 0: return M.MetricSamplingRate.off;
+          case 1: return M.MetricSamplingRate.e100ms;
+          case 10: return M.MetricSamplingRate.e1s;
+          case 20: return M.MetricSamplingRate.e2s;
+          case 40: return M.MetricSamplingRate.e4s;
+          case 80: return M.MetricSamplingRate.e8s;
+        }
+      }
+    }
+    throw new Exception('Sampling for isolate ${i.id} is not started');
+  }
+
+  void setSamplingRate(M.IsolateRef i, M.Metric m, M.MetricSamplingRate r) {
+    if (_rates.containsKey(i)) {
+      final metrics = _rates[i];
+      if (metrics.containsKey(m)) {
+        metrics[m] = _rateToInteger(r);
+      }
+    } else {
+      throw new Exception('Sampling for isolate ${i.id} is not started');
+    }
+  }
+
+  M.MetricBufferSize getBufferSize(M.IsolateRef i, M.Metric m) {
+    if (_sizes.containsKey(i)) {
+      final metrics = _sizes[i];
+      if (metrics.containsKey(m)) {
+        switch (metrics[m]) {
+          case 10: return M.MetricBufferSize.n10samples;
+          case 100: return M.MetricBufferSize.n100samples;
+          case 1000: return M.MetricBufferSize.n1000samples;
+        }
+      }
+    }
+    throw new Exception('Sampling for isolate ${i.id} is not started');
+  }
+
+  void setBufferSize(M.IsolateRef i, M.Metric m, M.MetricBufferSize s) {
+    if (_sizes.containsKey(i)) {
+      final metrics = _sizes[i];
+      if (metrics.containsKey(m)) {
+        metrics[m] = _sizeToInteger(s);
+      }
+    } else {
+      throw new Exception('Sampling for isolate ${i.id} is not started');
+    }
+  }
+
+  static int _rateToInteger(M.MetricSamplingRate r) {
+    switch (r) {
+      case M.MetricSamplingRate.off: return 0;
+      case M.MetricSamplingRate.e100ms: return 1;
+      case M.MetricSamplingRate.e1s: return 10;
+      case M.MetricSamplingRate.e2s: return 20;
+      case M.MetricSamplingRate.e4s: return 40;
+      case M.MetricSamplingRate.e8s: return 80;
+    }
+    throw new Exception('Unknown MetricSamplingRate ($r)');
+  }
+
+  static int _sizeToInteger(M.MetricBufferSize s) {
+    switch (s) {
+      case M.MetricBufferSize.n10samples: return 10;
+      case M.MetricBufferSize.n100samples: return 100;
+      case M.MetricBufferSize.n1000samples: return 1000;
+    }
+    throw new Exception('Unknown MetricBufferSize ($s)');
+  }
+
+  Iterable<M.MetricSample> getSamples(M.IsolateRef i, M.Metric m) {
+    if (_samples.containsKey(i)) {
+      final metrics = _samples[i];
+      if (metrics.containsKey(m)) {
+        return metrics[m];
+      }
+    }
+    return null;
+  }
+
+  double getMinValue(M.IsolateRef i, M.Metric m) {
+    Metric metric = m as Metric;
+    assert(metric != null);
+    return metric.internal.min;
+  }
+
+  double getMaxValue(M.IsolateRef i, M.Metric m) {
+    Metric metric = m as Metric;
+    assert(metric != null);
+    return metric.internal.max;
+  }
+
+  void _update(_) {
+    for (final isolate in _rates.keys) {
+      final metrics = _rates[isolate];
+      for (final metric in metrics.keys) {
+        final rate = metrics[metric];
+        if (rate != 0 && count % rate == 0) {
+          final size = _sizes[isolate][metric];
+          final samples = _samples[isolate][metric];
+          metric.internal.reload().then((m) {
+            if (samples.length >= size) {
+              samples.removeRange(0, samples.length - size + 1);
+            }
+            samples.add(new MetricSample(m.value));
+          });
+        }
+      }
+    }
+    ++count;
+  }
+}
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index a57dda7..a519ed9 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -93,7 +93,7 @@
 }
 
 /// A [ServiceObject] represents a persistent object within the vm.
-abstract class ServiceObject extends Observable {
+abstract class ServiceObject {
   static int LexicalSortName(ServiceObject o1, ServiceObject o2) {
     return o1.name.compareTo(o2.name);
   }
@@ -104,25 +104,25 @@
 
   /// The owner of this [ServiceObject].  This can be an [Isolate], a
   /// [VM], or null.
-  @reflectable ServiceObjectOwner get owner => _owner;
+  ServiceObjectOwner get owner => _owner;
   ServiceObjectOwner _owner;
 
   /// The [VM] which owns this [ServiceObject].
-  @reflectable VM get vm => _owner.vm;
+  VM get vm => _owner.vm;
 
   /// The [Isolate] which owns this [ServiceObject].  May be null.
-  @reflectable Isolate get isolate => _owner.isolate;
+  Isolate get isolate => _owner.isolate;
 
   /// The id of this object.
-  @reflectable String get id => _id;
+  String get id => _id;
   String _id;
 
   /// The user-level type of this object.
-  @reflectable String get type => _type;
+  String get type => _type;
   String _type;
 
   /// The vm type of this object.
-  @reflectable String get vmType => _vmType;
+  String get vmType => _vmType;
   String _vmType;
 
   bool get isICData => vmType == 'ICData';
@@ -167,15 +167,15 @@
   /// Is this object immutable after it is [loaded]?
   bool get immutable => false;
 
-  @observable String name;
-  @observable String vmName;
+  String name;
+  String vmName;
 
   /// Creates an empty [ServiceObject].
   ServiceObject._empty(this._owner);
 
   /// Creates a [ServiceObject] initialized from [map].
   factory ServiceObject._fromMap(ServiceObjectOwner owner,
-                                 ObservableMap map) {
+                                 Map map) {
     if (map == null) {
       return null;
     }
@@ -298,7 +298,7 @@
 
   Future<ServiceObject> _inProgressReload;
 
-  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) {
+  Future<Map> _fetchDirect({int count: kDefaultFieldLimit}) {
     Map params = {
       'objectId': id,
       'count': count,
@@ -323,7 +323,7 @@
     if (_inProgressReload == null) {
       var completer = new Completer<ServiceObject>();
       _inProgressReload = completer.future;
-      _fetchDirect(count: count).then((ObservableMap map) {
+      _fetchDirect(count: count).then((Map map) {
         var mapType = _stripRef(map['type']);
         if (mapType == 'Sentinel') {
           // An object may have been collected, etc.
@@ -348,7 +348,7 @@
   }
 
   /// Update [this] using [map] as a source. [map] can be a reference.
-  void update(ObservableMap map) {
+  void update(Map map) {
     assert(_isServiceMap(map));
 
     // Don't allow the type to change on an object update.
@@ -378,7 +378,7 @@
   }
 
   // Updates internal state from [map]. [map] can be a reference.
-  void _update(ObservableMap map, bool mapIsRef);
+  void _update(Map map, bool mapIsRef);
 
   // Helper that can be passed to .catchError that ignores the error.
   _ignoreError(error, stackTrace) {
@@ -387,13 +387,13 @@
 }
 
 abstract class HeapObject extends ServiceObject implements M.Object {
-  @observable Class clazz;
-  @observable int size;
-  @observable int retainedSize;
+  Class clazz;
+  int size;
+  int retainedSize;
 
   HeapObject._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     if (map['class'] != null) {
       // Sent with refs for some types. Load it if available, but don't clobber
       // it with null for kinds that only send if for full responses.
@@ -427,7 +427,7 @@
   /// Builds a [ServiceObject] corresponding to the [id] from [map].
   /// The result may come from the cache.  The result will not necessarily
   /// be [loaded].
-  ServiceObject getFromMap(ObservableMap map);
+  ServiceObject getFromMap(Map map);
 }
 
 abstract class Location implements M.Location {
@@ -454,7 +454,7 @@
 
   SourceLocation._empty(ServiceObject owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     assert(!mapIsRef);
     _upgradeCollection(map, owner);
     script = map['script'];
@@ -510,7 +510,7 @@
 
   UnresolvedSourceLocation._empty(ServiceObject owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     assert(!mapIsRef);
     _upgradeCollection(map, owner);
     script = map['script'];
@@ -619,8 +619,8 @@
 
 /// State for a VM being inspected.
 abstract class VM extends ServiceObjectOwner implements M.VM {
-  @reflectable VM get vm => this;
-  @reflectable Isolate get isolate => null;
+  VM get vm => this;
+  Isolate get isolate => null;
 
   // TODO(turnidge): The connection should not be stored in the VM object.
   bool get isDisconnected;
@@ -630,24 +630,23 @@
 
   // TODO(johnmccutchan): Ensure that isolates do not end up in _cache.
   Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
-  final ObservableMap<String,Isolate> _isolateCache =
-      new ObservableMap<String,Isolate>();
+  final Map<String,Isolate> _isolateCache = <String,Isolate>{};
 
   // The list of live isolates, ordered by isolate start time.
-  final ObservableList<Isolate> isolates = new ObservableList<Isolate>();
+  final List<Isolate> isolates = <Isolate>[];
 
-  @observable String version = 'unknown';
-  @observable String hostCPU;
-  @observable String targetCPU;
-  @observable int architectureBits;
-  @observable bool assertsEnabled = false;
-  @observable bool typeChecksEnabled = false;
-  @observable int pid = 0;
-  @observable int maxRSS = 0;
-  @observable bool profileVM = false;
-  @observable DateTime startTime;
-  @observable DateTime refreshTime;
-  @observable Duration get upTime {
+  String version = 'unknown';
+  String hostCPU;
+  String targetCPU;
+  int architectureBits;
+  bool assertsEnabled = false;
+  bool typeChecksEnabled = false;
+  int pid = 0;
+  int maxRSS = 0;
+  bool profileVM = false;
+  DateTime startTime;
+  DateTime refreshTime;
+  Duration get upTime {
     if (startTime == null) {
       return null;
     }
@@ -655,11 +654,11 @@
   }
 
   VM() : super._empty(null) {
-    update(toObservable({'name':'vm', 'type':'@VM'}));
+    update({'name':'vm', 'type':'@VM'});
   }
 
   void postServiceEvent(String streamId, Map response, ByteData data) {
-    var map = toObservable(response);
+    var map = response;
     assert(!map.containsKey('_data'));
     if (data != null) {
       map['_data'] = data;
@@ -737,7 +736,7 @@
 
   static final String _isolateIdPrefix = 'isolates/';
 
-  ServiceObject getFromMap(ObservableMap map) {
+  ServiceObject getFromMap(Map map) {
     if (map == null) {
       return null;
     }
@@ -786,9 +785,9 @@
   // Implemented in subclass.
   Future<Map> invokeRpcRaw(String method, Map params);
 
-  Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
+  Future<Map> invokeRpcNoUpgrade(String method, Map params) {
     return invokeRpcRaw(method, params).then((Map response) {
-      var map = toObservable(response);
+      var map = response;
       if (Tracer.current != null) {
         Tracer.current.trace("Received response for ${method}/${params}}",
                              map:map);
@@ -807,7 +806,7 @@
   }
 
   Future<ServiceObject> invokeRpc(String method, Map params) {
-    return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
+    return invokeRpcNoUpgrade(method, params).then((Map response) {
       var obj = new ServiceObject._fromMap(this, response);
       if ((obj != null) && obj.canCache) {
         String objId = obj.id;
@@ -828,7 +827,7 @@
     return invokeRpc('_restartVM', {});
   }
 
-  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) async {
+  Future<Map> _fetchDirect({int count: kDefaultFieldLimit}) async {
     if (!loaded) {
       // The vm service relies on these events to keep the VM and
       // Isolate types up to date.
@@ -901,7 +900,7 @@
   /// Completes when the VM disconnects or there was an error connecting.
   Future get onDisconnect;
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     name = map['name'];
     vmName = map.containsKey('_vmName') ? map['_vmName'] : name;
     if (mapIsRef) {
@@ -919,7 +918,6 @@
     int startTimeMillis = map['startTime'];
     startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeMillis);
     refreshTime = new DateTime.now();
-    notifyPropertyChange(#upTime, 0, 1);
     pid = map['pid'];
     maxRSS = map['_maxRSS'];
     profileVM = map['_profilerMode'] == 'VM';
@@ -1062,7 +1060,7 @@
 
   TagProfile(this._historySize);
 
-  void _processTagProfile(double seconds, ObservableMap tagProfile) {
+  void _processTagProfile(double seconds, Map tagProfile) {
     _seconds = seconds;
     var counters = tagProfile['counters'];
     if (names.length == 0) {
@@ -1184,13 +1182,13 @@
       object = map['object'];
 }
 
-class HeapSpace extends Observable implements M.HeapSpace {
-  @observable int used = 0;
-  @observable int capacity = 0;
-  @observable int external = 0;
-  @observable int collections = 0;
-  @observable double totalCollectionTimeInSeconds = 0.0;
-  @observable double averageCollectionPeriodInMillis = 0.0;
+class HeapSpace implements M.HeapSpace {
+  int used = 0;
+  int capacity = 0;
+  int external = 0;
+  int collections = 0;
+  double totalCollectionTimeInSeconds = 0.0;
+  double averageCollectionPeriodInMillis = 0.0;
 
   Duration get avgCollectionTime {
     final mcs = totalCollectionTimeInSeconds * Duration.MICROSECONDS_PER_SECOND
@@ -1230,19 +1228,19 @@
   static const kLoggingStream = '_Logging';
   static const kExtensionStream = 'Extension';
 
-  @reflectable VM get vm => owner;
-  @reflectable Isolate get isolate => this;
-  @observable int number;
-  @observable int originNumber;
-  @observable DateTime startTime;
-  @observable Duration get upTime {
+  VM get vm => owner;
+  Isolate get isolate => this;
+  int number;
+  int originNumber;
+  DateTime startTime;
+  Duration get upTime {
     if (startTime == null) {
       return null;
     }
     return (new DateTime.now().difference(startTime));
   }
 
-  @observable Map counters = {};
+  Map counters = {};
 
   void _updateRunState() {
     topFrame = M.topFrame(pauseEvent);
@@ -1250,20 +1248,16 @@
               !(pauseEvent is M.ResumeEvent));
     running = (!paused && topFrame != null);
     idle = (!paused && topFrame == null);
-    notifyPropertyChange(#topFrame, 0, 1);
-    notifyPropertyChange(#paused, 0, 1);
-    notifyPropertyChange(#running, 0, 1);
-    notifyPropertyChange(#idle, 0, 1);
   }
 
-  @observable M.DebugEvent pauseEvent = null;
-  @observable bool paused = false;
-  @observable bool running = false;
-  @observable bool idle = false;
-  @observable bool loading = true;
-  @observable bool runnable = false;
-  @observable bool ioEnabled = false;
-  @observable bool reloading = false;
+  M.DebugEvent pauseEvent = null;
+  bool paused = false;
+  bool running = false;
+  bool idle = false;
+  bool loading = true;
+  bool runnable = false;
+  bool ioEnabled = false;
+  bool reloading = false;
   M.IsolateStatus get status {
     if (paused) {
       return M.IsolateStatus.paused;
@@ -1399,7 +1393,7 @@
 
   Class getClassByCid(int cid) => _classesByCid[cid];
 
-  ServiceObject getFromMap(ObservableMap map) {
+  ServiceObject getFromMap(Map map) {
     if (map == null) {
       return null;
     }
@@ -1422,13 +1416,13 @@
     return obj;
   }
 
-  Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
+  Future<Map> invokeRpcNoUpgrade(String method, Map params) {
     params['isolateId'] = id;
     return vm.invokeRpcNoUpgrade(method, params);
   }
 
   Future<ServiceObject> invokeRpc(String method, Map params) {
-    return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
+    return invokeRpcNoUpgrade(method, params).then((Map response) {
       return getFromMap(response);
     });
   }
@@ -1452,29 +1446,28 @@
     return isolate.invokeRpc('getObject', params);
   }
 
-  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) async {
+  Future<Map> _fetchDirect({int count: kDefaultFieldLimit}) async {
     return invokeRpcNoUpgrade('getIsolate', {});
   }
 
-  @observable Class objectClass;
-  @observable final rootClasses = new ObservableList<Class>();
+  Class objectClass;
+  final rootClasses = <Class>[];
   Map<int, Class> _classesByCid = new Map<int, Class>();
 
-  @observable Library rootLibrary;
-  @observable ObservableList<Library> libraries =
-      new ObservableList<Library>();
-  @observable Frame topFrame;
+  Library rootLibrary;
+  List<Library> libraries = <Library>[];
+  Frame topFrame;
 
-  @observable String name;
-  @observable String vmName;
-  @observable ServiceFunction entry;
+  String name;
+  String vmName;
+  ServiceFunction entry;
 
   final HeapSpace newSpace = new HeapSpace();
   final HeapSpace oldSpace = new HeapSpace();
 
-  @observable String fileAndLine;
+  String fileAndLine;
 
-  @observable DartError error;
+  DartError error;
   StreamController _snapshotFetch;
 
   List<ByteData> _chunksInProgress;
@@ -1520,12 +1513,12 @@
     return _snapshotFetch.stream;
   }
 
-  void updateHeapsFromMap(ObservableMap map) {
+  void updateHeapsFromMap(Map map) {
     newSpace.update(map['new']);
     oldSpace.update(map['old']);
   }
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     name = map['name'];
     vmName = map.containsKey('_vmName') ? map['_vmName'] : name;
     number = int.parse(map['number'], onError:(_) => null);
@@ -1544,7 +1537,6 @@
     var savedStartTime = startTime;
     int startTimeInMillis = map['startTime'];
     startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeInMillis);
-    notifyPropertyChange(#upTime, 0, 1);
     var countersMap = map['_tagCounters'];
     if (countersMap != null) {
       var names = countersMap['names'];
@@ -1599,14 +1591,14 @@
 
   Future<TagProfile> updateTagProfile() {
     return isolate.invokeRpcNoUpgrade('_getTagProfile', {}).then(
-      (ObservableMap map) {
+      (Map map) {
         var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0;
         tagProfile._processTagProfile(seconds, map);
         return tagProfile;
       });
   }
 
-  ObservableMap<int, Breakpoint> breakpoints = new ObservableMap();
+  Map<int, Breakpoint> breakpoints = <int, Breakpoint>{};
   String exceptionsPauseInfo;
 
   void _updateBreakpoints(List newBpts) {
@@ -1842,15 +1834,13 @@
     return invokeRpc('_getObjectByAddress', params);
   }
 
-  final ObservableMap<String, ServiceMetric> dartMetrics =
-      new ObservableMap<String, ServiceMetric>();
+  final Map<String, ServiceMetric> dartMetrics = <String, ServiceMetric>{};
 
-  final ObservableMap<String, ServiceMetric> nativeMetrics =
-      new ObservableMap<String, ServiceMetric>();
+  final Map<String, ServiceMetric> nativeMetrics = <String, ServiceMetric>{};
 
-  Future<ObservableMap<String, ServiceMetric>> _refreshMetrics(
+  Future<Map<String, ServiceMetric>> _refreshMetrics(
       String metricType,
-      ObservableMap<String, ServiceMetric> metricsMap) {
+      Map<String, ServiceMetric> metricsMap) {
     return invokeRpc('_getIsolateMetricList',
                      { 'type': metricType }).then((result) {
       // Clear metrics map.
@@ -1864,11 +1854,11 @@
     });
   }
 
-  Future<ObservableMap<String, ServiceMetric>> refreshDartMetrics() {
+  Future<Map<String, ServiceMetric>> refreshDartMetrics() {
     return _refreshMetrics('Dart', dartMetrics);
   }
 
-  Future<ObservableMap<String, ServiceMetric>> refreshNativeMetrics() {
+  Future<Map<String, ServiceMetric>> refreshNativeMetrics() {
     return _refreshMetrics('Native', nativeMetrics);
   }
 
@@ -1888,11 +1878,11 @@
 
 
 class ObjectStore extends ServiceObject implements M.ObjectStore {
-  @observable List<NamedField> fields = new List<NamedField>();
+  List<NamedField> fields = new List<NamedField>();
 
   ObjectStore._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     // Extract full properties.
     _upgradeCollection(map, isolate);
 
@@ -1909,17 +1899,16 @@
 }
 
 
-/// A [ServiceObject] which implements [ObservableMap].
-class ServiceMap extends ServiceObject implements ObservableMap,
-                                                  M.UnknownObjectRef  {
-  final ObservableMap _map = new ObservableMap();
+/// A [ServiceObject] which implements [Map].
+class ServiceMap extends ServiceObject implements Map, M.UnknownObjectRef  {
+  final Map _map = {};
   static String objectIdRingPrefix = 'objects/';
 
   bool get immutable => false;
 
   ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _loaded = !mapIsRef;
 
     _upgradeCollection(map, owner);
@@ -1954,16 +1943,6 @@
   Iterable get values => _map.values;
   int get length => _map.length;
 
-  // Forward ChangeNotifier interface calls.
-  bool deliverChanges() => _map.deliverChanges();
-  void notifyChange(ChangeRecord record) => _map.notifyChange(record);
-  notifyPropertyChange(Symbol field, Object oldValue, Object newValue) =>
-      _map.notifyPropertyChange(field, oldValue, newValue);
-  void observed() => _map.observed();
-  void unobserved() => _map.unobserved();
-  Stream<List<ChangeRecord>> get changes => _map.changes;
-  bool get hasObservers => _map.hasObservers;
-
   String toString() => "ServiceMap($_map)";
 }
 
@@ -1985,11 +1964,11 @@
   M.ErrorKind kind;
   final M.ClassRef clazz = null;
   final int size = null;
-  @observable String message;
-  @observable Instance exception;
-  @observable Instance stacktrace;
+  String message;
+  Instance exception;
+  Instance stacktrace;
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     message = map['message'];
     kind = stringToErrorKind(map['kind']);
     exception = new ServiceObject._fromMap(owner, map['exception']);
@@ -2045,32 +2024,32 @@
     kind = kConnectionClosed;
   }
 
-  @observable String kind;
-  @observable DateTime timestamp;
+  String kind;
+  DateTime timestamp;
   List<M.Breakpoint> pauseBreakpoints;
-  @observable Breakpoint breakpoint;
-  @observable Frame topFrame;
-  @observable DartError error;
-  @observable String extensionRPC;
-  @observable Instance exception;
-  @observable Instance reloadError;
-  @observable bool atAsyncSuspension;
-  @observable Instance inspectee;
-  @observable ByteData data;
-  @observable int count;
-  @observable String reason;
-  @observable String exceptions;
-  @observable String bytesAsString;
-  @observable Map logRecord;
-  @observable String extensionKind;
-  @observable Map extensionData;
-  @observable List timelineEvents;
-  @observable String spawnToken;
-  @observable String spawnError;
+  Breakpoint breakpoint;
+  Frame topFrame;
+  DartError error;
+  String extensionRPC;
+  Instance exception;
+  Instance reloadError;
+  bool atAsyncSuspension;
+  Instance inspectee;
+  ByteData data;
+  int count;
+  String reason;
+  String exceptions;
+  String bytesAsString;
+  Map logRecord;
+  String extensionKind;
+  Map extensionData;
+  List timelineEvents;
+  String spawnToken;
+  String spawnError;
 
   int chunkIndex, chunkCount, nodeCount;
 
-  @observable bool get isPauseEvent {
+  bool get isPauseEvent {
     return (kind == kPauseStart ||
             kind == kPauseExit ||
             kind == kPauseBreakpoint ||
@@ -2079,7 +2058,7 @@
             kind == kNone);
   }
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _loaded = true;
     _upgradeCollection(map, owner);
 
@@ -2087,7 +2066,6 @@
     timestamp =
         new DateTime.fromMillisecondsSinceEpoch(map['timestamp']);
     kind = map['kind'];
-    notifyPropertyChange(#isPauseEvent, 0, 1);
     name = 'ServiceEvent $kind';
     vmName = name;
     if (map['breakpoint'] != null) {
@@ -2183,22 +2161,22 @@
   bool get immutable => false;
 
   // A unique integer identifier for this breakpoint.
-  @observable int number;
+  int number;
 
   // Either SourceLocation or UnresolvedSourceLocation.
-  @observable Location location;
+  Location location;
 
   // The breakpoint is in a file which is not yet loaded.
-  @observable bool latent;
+  bool latent;
 
   // The breakpoint has been assigned to a final source location.
-  @observable bool resolved;
+  bool resolved;
 
   // The breakpoint was synthetically created as part of an
   // 'OverAsyncContinuation' resume request.
-  @observable bool isSyntheticAsyncContinuation;
+  bool isSyntheticAsyncContinuation;
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _loaded = true;
     _upgradeCollection(map, owner);
 
@@ -2248,10 +2226,10 @@
 
 
 class LibraryDependency implements M.LibraryDependency {
-  @reflectable final bool isImport;
-  @reflectable final bool isDeferred;
-  @reflectable final String prefix;
-  @reflectable final Library target;
+  final bool isImport;
+  final bool isDeferred;
+  final String prefix;
+  final Library target;
 
   bool get isExport => !isImport;
 
@@ -2265,12 +2243,12 @@
 
 
 class Library extends HeapObject implements M.Library {
-  @observable String uri;
-  @reflectable final dependencies = new ObservableList<LibraryDependency>();
-  @reflectable final scripts = new ObservableList<Script>();
-  @reflectable final classes = new ObservableList<Class>();
-  @reflectable final variables = new ObservableList<Field>();
-  @reflectable final functions = new ObservableList<ServiceFunction>();
+  String uri;
+  final dependencies = <LibraryDependency>[];
+  final scripts = <Script>[];
+  final classes = <Class>[];
+  final variables = <Field>[];
+  final functions = <ServiceFunction>[];
 
   bool get immutable => false;
 
@@ -2280,7 +2258,7 @@
 
   Library._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -2329,9 +2307,9 @@
   String toString() => "Library($uri)";
 }
 
-class AllocationCount extends Observable implements M.AllocationCount {
-  @observable int instances = 0;
-  @observable int bytes = 0;
+class AllocationCount implements M.AllocationCount {
+  int instances = 0;
+  int bytes = 0;
 
   void reset() {
     instances = 0;
@@ -2368,41 +2346,41 @@
 }
 
 class Class extends HeapObject implements M.Class {
-  @observable Library library;
+  Library library;
 
-  @observable bool isAbstract;
-  @observable bool isConst;
-  @observable bool isFinalized;
-  @observable bool isPatch;
-  @observable bool isImplemented;
+  bool isAbstract;
+  bool isConst;
+  bool isFinalized;
+  bool isPatch;
+  bool isImplemented;
 
-  @observable SourceLocation location;
+  SourceLocation location;
 
-  @observable DartError error;
-  @observable int vmCid;
+  DartError error;
+  int vmCid;
 
   final Allocations newSpace = new Allocations();
   final Allocations oldSpace = new Allocations();
   final AllocationCount promotedByLastNewGC = new AllocationCount();
 
-  @observable bool get hasAllocations => newSpace.notEmpty || oldSpace.notEmpty;
-  @observable bool get hasNoAllocations => newSpace.empty && oldSpace.empty;
-  @observable bool traceAllocations = false;
-  @reflectable final fields = new ObservableList<Field>();
-  @reflectable final functions = new ObservableList<ServiceFunction>();
+  bool get hasAllocations => newSpace.notEmpty || oldSpace.notEmpty;
+  bool get hasNoAllocations => newSpace.empty && oldSpace.empty;
+  bool traceAllocations = false;
+  final fields = <Field>[];
+  final functions = <ServiceFunction>[];
 
-  @observable Class superclass;
-  @reflectable final interfaces = new ObservableList<Instance>();
-  @reflectable final subclasses = new ObservableList<Class>();
+  Class superclass;
+  final interfaces = <Instance>[];
+  final subclasses = <Class>[];
 
-  @observable Instance superType;
-  @observable Instance mixin;
+  Instance superType;
+  Instance mixin;
 
   bool get immutable => false;
 
   Class._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -2472,7 +2450,6 @@
     if (allocationStats != null) {
       newSpace.update(allocationStats['new']);
       oldSpace.update(allocationStats['old']);
-      notifyPropertyChange(#hasNoAllocations, 0, 1);
       promotedByLastNewGC.instances = allocationStats['promotedInstances'];
       promotedByLastNewGC.bytes = allocationStats['promotedBytes'];
     }
@@ -2623,41 +2600,41 @@
 }
 
 class Instance extends HeapObject implements M.Instance {
-  @observable M.InstanceKind kind;
-  @observable String valueAsString;  // If primitive.
-  @observable bool valueAsStringIsTruncated;
-  @observable ServiceFunction closureFunction;  // If a closure.
-  @observable Context closureContext;  // If a closure.
-  @observable int length; // If a List, Map or TypedData.
+  M.InstanceKind kind;
+  String valueAsString;  // If primitive.
+  bool valueAsStringIsTruncated;
+  ServiceFunction closureFunction;  // If a closure.
+  Context closureContext;  // If a closure.
+  int length; // If a List, Map or TypedData.
   int count;
   int offset;
-  @observable Instance pattern;  // If a RegExp.
+  Instance pattern;  // If a RegExp.
 
-  @observable String name;
-  @observable Class typeClass;
-  @observable Class parameterizedClass;
-  @observable TypeArguments typeArguments;
-  @observable int parameterIndex;
-  @observable Instance targetType;
-  @observable Instance bound;
+  String name;
+  Class typeClass;
+  Class parameterizedClass;
+  TypeArguments typeArguments;
+  int parameterIndex;
+  Instance targetType;
+  Instance bound;
 
-  @observable Iterable<BoundField> fields;
-  @observable var nativeFields;
-  @observable Iterable<Guarded<HeapObject>> elements;  // If a List.
-  @observable Iterable<MapAssociation> associations;  // If a Map.
-  @observable Iterable<dynamic> typedElements;  // If a TypedData.
-  @observable HeapObject referent;  // If a MirrorReference.
-  @observable Instance key;  // If a WeakProperty.
-  @observable Instance value;  // If a WeakProperty.
-  @observable Breakpoint activationBreakpoint;  // If a Closure.
-  @observable ServiceFunction oneByteFunction;  // If a RegExp.
-  @observable ServiceFunction twoByteFunction;  // If a RegExp.
-  @observable ServiceFunction externalOneByteFunction;  // If a RegExp.
-  @observable ServiceFunction externalTwoByteFunction;  // If a RegExp.
-  @observable Instance oneByteBytecode;  // If a RegExp.
-  @observable Instance twoByteBytecode;  // If a RegExp.
-  @observable bool isCaseSensitive;  // If a RegExp.
-  @observable bool isMultiLine;  // If a RegExp.
+  Iterable<BoundField> fields;
+  var nativeFields;
+  Iterable<Guarded<HeapObject>> elements;  // If a List.
+  Iterable<MapAssociation> associations;  // If a Map.
+  Iterable<dynamic> typedElements;  // If a TypedData.
+  HeapObject referent;  // If a MirrorReference.
+  Instance key;  // If a WeakProperty.
+  Instance value;  // If a WeakProperty.
+  Breakpoint activationBreakpoint;  // If a Closure.
+  ServiceFunction oneByteFunction;  // If a RegExp.
+  ServiceFunction twoByteFunction;  // If a RegExp.
+  ServiceFunction externalOneByteFunction;  // If a RegExp.
+  ServiceFunction externalTwoByteFunction;  // If a RegExp.
+  Instance oneByteBytecode;  // If a RegExp.
+  Instance twoByteBytecode;  // If a RegExp.
+  bool isCaseSensitive;  // If a RegExp.
+  bool isMultiLine;  // If a RegExp.
 
   bool get isAbstractType => M.isAbstractType(kind);
   bool get isNull => kind == M.InstanceKind.vNull;
@@ -2704,7 +2681,7 @@
 
   Instance._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     // Extract full properties.1
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
@@ -2832,13 +2809,13 @@
 
 
 class Context extends HeapObject implements M.Context {
-  @observable Context parentContext;
-  @observable int length;
-  @observable Iterable<ContextElement> variables;
+  Context parentContext;
+  int length;
+  Iterable<ContextElement> variables;
 
   Context._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     // Extract full properties.
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
@@ -2863,7 +2840,7 @@
 class ContextElement extends M.ContextElement {
   final Guarded<Instance> value;
 
-  ContextElement(ObservableMap map)
+  ContextElement(Map map)
     : value = new Guarded<Instance>(map['value']);
 }
 
@@ -2895,32 +2872,32 @@
 
 class ServiceFunction extends HeapObject implements M.Function {
   // owner is a Library, Class, or ServiceFunction.
-  @observable M.ObjectRef dartOwner;
-  @observable Library library;
-  @observable bool isStatic;
-  @observable bool isConst;
-  @observable SourceLocation location;
-  @observable Code code;
-  @observable Code unoptimizedCode;
-  @observable bool isOptimizable;
-  @observable bool isInlinable;
-  @observable bool hasIntrinsic;
-  @observable bool isRecognized;
-  @observable bool isNative;
-  @observable M.FunctionKind kind;
-  @observable int deoptimizations;
-  @observable String qualifiedName;
-  @observable int usageCounter;
-  @observable bool isDart;
-  @observable ProfileFunction profile;
-  @observable Instance icDataArray;
-  @observable Field field;
+  M.ObjectRef dartOwner;
+  Library library;
+  bool isStatic;
+  bool isConst;
+  SourceLocation location;
+  Code code;
+  Code unoptimizedCode;
+  bool isOptimizable;
+  bool isInlinable;
+  bool hasIntrinsic;
+  bool isRecognized;
+  bool isNative;
+  M.FunctionKind kind;
+  int deoptimizations;
+  String qualifiedName;
+  int usageCounter;
+  bool isDart;
+  ProfileFunction profile;
+  Instance icDataArray;
+  Field field;
 
   bool get immutable => false;
 
   ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3003,7 +2980,7 @@
 
   Sentinel._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     // Extract full properties.
     _upgradeCollection(map, isolate);
 
@@ -3013,29 +2990,30 @@
   }
 
   String toString() => 'Sentinel($kind)';
+  String get shortName => valueAsString;
 }
 
 class Field extends HeapObject implements M.Field {
   // Library or Class.
-  @observable HeapObject dartOwner;
-  @observable Library library;
-  @observable Instance declaredType;
-  @observable bool isStatic;
-  @observable bool isFinal;
-  @observable bool isConst;
-  @observable Instance staticValue;
-  @observable String name;
-  @observable String vmName;
+  HeapObject dartOwner;
+  Library library;
+  Instance declaredType;
+  bool isStatic;
+  bool isFinal;
+  bool isConst;
+  Instance staticValue;
+  String name;
+  String vmName;
 
-  @observable bool guardNullable;
+  bool guardNullable;
   M.GuardClassKind guardClassKind;
-  @observable Class guardClass;
-  @observable String guardLength;
-  @observable SourceLocation location;
+  Class guardClass;
+  String guardLength;
+  SourceLocation location;
 
   Field._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     // Extract full properties.
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
@@ -3086,11 +3064,11 @@
 }
 
 
-class ScriptLine extends Observable {
+class ScriptLine {
   final Script script;
   final int line;
   final String text;
-  @observable Set<Breakpoint> breakpoints;
+  Set<Breakpoint> breakpoints;
 
   ScriptLine(this.script, this.line, this.text);
 
@@ -3220,15 +3198,15 @@
 }
 
 class Script extends HeapObject implements M.Script {
-  final lines = new ObservableList<ScriptLine>();
-  @observable String uri;
-  @observable String kind;
-  @observable DateTime loadTime;
-  @observable int firstTokenPos;
-  @observable int lastTokenPos;
-  @observable int lineOffset;
-  @observable int columnOffset;
-  @observable Library library;
+  final lines = <ScriptLine>[];
+  String uri;
+  String kind;
+  DateTime loadTime;
+  int firstTokenPos;
+  int lastTokenPos;
+  int lineOffset;
+  int columnOffset;
+  Library library;
 
   String source;
 
@@ -3315,7 +3293,7 @@
     return c >= 48 && c <= 75; // Digit
   }
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3391,9 +3369,6 @@
         _addBreakpoint(bpt);
       }
     }
-
-    // Notify any Observers that this Script's state has changed.
-    notifyChange(null);
   }
 
   void _addBreakpoint(Breakpoint bpt) {
@@ -3545,25 +3520,25 @@
   }
 }
 
-class PcDescriptor extends Observable {
+class PcDescriptor {
   final int pcOffset;
-  @reflectable final int deoptId;
-  @reflectable final int tokenPos;
-  @reflectable final int tryIndex;
-  @reflectable final String kind;
-  @observable Script script;
-  @observable String formattedLine;
+  final int deoptId;
+  final int tokenPos;
+  final int tryIndex;
+  final String kind;
+  Script script;
+  String formattedLine;
   PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex,
                this.kind);
 
-  @reflectable String formattedDeoptId() {
+  String formattedDeoptId() {
     if (deoptId == -1) {
       return 'N/A';
     }
     return deoptId.toString();
   }
 
-  @reflectable String formattedTokenPos() {
+  String formattedTokenPos() {
     if (tokenPos == -1) {
       return '';
     }
@@ -3586,16 +3561,15 @@
 }
 
 class PcDescriptors extends ServiceObject implements M.PcDescriptorsRef {
-  @observable Class clazz;
-  @observable int size;
+  Class clazz;
+  int size;
   bool get immutable => true;
-  @reflectable final List<PcDescriptor> descriptors =
-      new ObservableList<PcDescriptor>();
+  final List<PcDescriptor> descriptors = <PcDescriptor>[];
 
   PcDescriptors._empty(ServiceObjectOwner owner) : super._empty(owner) {
   }
 
-  void _update(ObservableMap m, bool mapIsRef) {
+  void _update(Map m, bool mapIsRef) {
     if (mapIsRef) {
       return;
     }
@@ -3615,29 +3589,27 @@
   }
 }
 
-class LocalVarDescriptor extends Observable
-                         implements M.LocalVarDescriptorsRef {
-  @reflectable final String id;
-  @reflectable final String name;
-  @reflectable final int index;
-  @reflectable final int beginPos;
-  @reflectable final int endPos;
-  @reflectable final int scopeId;
-  @reflectable final String kind;
+class LocalVarDescriptor implements M.LocalVarDescriptorsRef {
+  final String id;
+  final String name;
+  final int index;
+  final int beginPos;
+  final int endPos;
+  final int scopeId;
+  final String kind;
 
   LocalVarDescriptor(this.id, this.name, this.index, this.beginPos, this.endPos,
                      this.scopeId, this.kind);
 }
 
 class LocalVarDescriptors extends ServiceObject {
-  @observable Class clazz;
-  @observable int size;
+  Class clazz;
+  int size;
   bool get immutable => true;
-  @reflectable final List<LocalVarDescriptor> descriptors =
-        new ObservableList<LocalVarDescriptor>();
+  final List<LocalVarDescriptor> descriptors = <LocalVarDescriptor>[];
   LocalVarDescriptors._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap m, bool mapIsRef) {
+  void _update(Map m, bool mapIsRef) {
     if (mapIsRef) {
       return;
     }
@@ -3663,12 +3635,12 @@
 class ObjectPool extends HeapObject implements M.ObjectPool {
   bool get immutable => false;
 
-  @observable int length;
-  @observable List<ObjectPoolEntry> entries;
+  int length;
+  List<ObjectPoolEntry> entries;
 
   ObjectPool._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3718,16 +3690,16 @@
 }
 
 class ICData extends HeapObject implements M.ICData {
-  @observable HeapObject dartOwner;
-  @observable String selector;
-  @observable Instance argumentsDescriptor;
-  @observable Instance entries;
+  HeapObject dartOwner;
+  String selector;
+  Instance argumentsDescriptor;
+  Instance entries;
 
   bool get immutable => false;
 
   ICData._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3748,7 +3720,7 @@
 
   TypeArguments._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3768,7 +3740,7 @@
 
   InstanceSet._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3781,16 +3753,16 @@
 }
 
 class MegamorphicCache extends HeapObject implements M.MegamorphicCache {
-  @observable int mask;
-  @observable Instance buckets;
-  @observable String selector;
-  @observable Instance argumentsDescriptor;
+  int mask;
+  Instance buckets;
+  String selector;
+  Instance argumentsDescriptor;
 
   bool get immutable => false;
 
   MegamorphicCache._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3808,11 +3780,11 @@
 class TokenStream extends HeapObject implements M.TokenStreamRef {
   bool get immutable => true;
 
-  @observable String privateKey;
+  String privateKey;
 
   TokenStream._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     _upgradeCollection(map, isolate);
     super._update(map, mapIsRef);
 
@@ -3823,15 +3795,14 @@
   }
 }
 
-class CodeInstruction extends Observable {
-  @observable final int address;
-  @observable final int pcOffset;
-  @observable final String machine;
-  @observable final String human;
-  @observable final ServiceObject object;
-  @observable CodeInstruction jumpTarget;
-  @reflectable List<PcDescriptor> descriptors =
-      new ObservableList<PcDescriptor>();
+class CodeInstruction {
+  final int address;
+  final int pcOffset;
+  final String machine;
+  final String human;
+  final ServiceObject object;
+  CodeInstruction jumpTarget;
+  List<PcDescriptor> descriptors = <PcDescriptor>[];
 
   CodeInstruction(this.address,
                   this.pcOffset,
@@ -3839,8 +3810,8 @@
                   this.human,
                   this.object);
 
-  @reflectable bool get isComment => address == 0;
-  @reflectable bool get hasDescriptors => descriptors.length > 0;
+  bool get isComment => address == 0;
+  bool get hasDescriptors => descriptors.length > 0;
 
   bool _isJumpInstruction() {
     return human.startsWith('j');
@@ -3912,24 +3883,22 @@
 }
 
 class Code extends HeapObject implements M.Code {
-  @observable M.CodeKind kind;
-  @observable ObjectPool objectPool;
-  @observable ServiceFunction function;
-  @observable Script script;
-  @observable bool isOptimized;
-  @observable bool hasIntrinsic;
-  @observable bool isNative;
+  M.CodeKind kind;
+  ObjectPool objectPool;
+  ServiceFunction function;
+  Script script;
+  bool isOptimized;
+  bool hasIntrinsic;
+  bool isNative;
 
-  @reflectable int startAddress = 0;
-  @reflectable int endAddress = 0;
-  @reflectable final instructions = new ObservableList<CodeInstruction>();
+  int startAddress = 0;
+  int endAddress = 0;
+  final instructions = <CodeInstruction>[];
   List<CodeInstruction> instructionsByAddressOffset;
 
-  @observable ProfileCode profile;
-  final List<CodeInlineInterval> inlineIntervals =
-      new List<CodeInlineInterval>();
-  final ObservableList<ServiceFunction> inlinedFunctions =
-      new ObservableList<ServiceFunction>();
+  ProfileCode profile;
+  final List<CodeInlineInterval> inlineIntervals = <CodeInlineInterval>[];
+  final List<ServiceFunction> inlinedFunctions = <ServiceFunction>[];
 
   bool get immutable => true;
 
@@ -3984,7 +3953,7 @@
     return new Future.value(this);
   }
 
-  void _update(ObservableMap m, bool mapIsRef) {
+  void _update(Map m, bool mapIsRef) {
     name = m['name'];
     vmName = (m.containsKey('_vmName') ? m['_vmName'] : name);
     isOptimized = m['_optimized'];
@@ -4063,7 +4032,7 @@
     }
   }
 
-  @observable bool hasDisassembly = false;
+  bool hasDisassembly = false;
 
   void _processDisassembly(List disassembly) {
     assert(disassembly != null);
@@ -4126,7 +4095,7 @@
     return (address >= startAddress) && (address < endAddress);
   }
 
-  @reflectable bool get isDartCode => (kind == M.CodeKind.dart) ||
+  bool get isDartCode => (kind == M.CodeKind.dart) ||
                                       (kind == M.CodeKind.stub);
 
   String toString() => 'Code($kind, $name)';
@@ -4159,11 +4128,11 @@
 
 /// A snapshot of statistics associated with a [Socket].
 class SocketStats {
-  @reflectable final int bytesRead;
-  @reflectable final int bytesWritten;
-  @reflectable final int readCalls;
-  @reflectable final int writeCalls;
-  @reflectable final int available;
+  final int bytesRead;
+  final int bytesWritten;
+  final int readCalls;
+  final int writeCalls;
+  final int available;
 
   SocketStats(this.bytesRead, this.bytesWritten,
               this.readCalls, this.writeCalls,
@@ -4178,31 +4147,31 @@
 
   ServiceObject socketOwner;
 
-  @reflectable bool get isPipe => (kind == SocketKind.Pipe);
+  bool get isPipe => (kind == SocketKind.Pipe);
 
-  @observable SocketStats latest;
-  @observable SocketStats previous;
+  SocketStats latest;
+  SocketStats previous;
 
-  @observable SocketKind kind;
+  SocketKind kind;
 
-  @observable String protocol = '';
+  String protocol = '';
 
-  @observable bool readClosed = false;
-  @observable bool writeClosed = false;
-  @observable bool closing = false;
+  bool readClosed = false;
+  bool writeClosed = false;
+  bool closing = false;
 
   /// Listening for connections.
-  @observable bool listening = false;
+  bool listening = false;
 
-  @observable int fd;
+  int fd;
 
-  @observable String localAddress;
-  @observable int localPort;
-  @observable String remoteAddress;
-  @observable int remotePort;
+  String localAddress;
+  int localPort;
+  String remoteAddress;
+  int remotePort;
 
   // Updates internal state from [map]. [map] can be a reference.
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     name = map['name'];
     vmName = map['name'];
 
@@ -4233,59 +4202,26 @@
   }
 }
 
-class MetricSample {
-  final double value;
-  final DateTime time;
-  MetricSample(this.value) : time = new DateTime.now();
-}
-
-class ServiceMetric extends ServiceObject {
+class ServiceMetric extends ServiceObject implements M.Metric {
   ServiceMetric._empty(ServiceObjectOwner owner) : super._empty(owner) {
   }
 
   bool get immutable => false;
 
-  @observable bool recording = false;
-  MetricPoller poller;
-
-  final ObservableList<MetricSample> samples =
-      new ObservableList<MetricSample>();
-  int _sampleBufferSize = 100;
-  int get sampleBufferSize => _sampleBufferSize;
-  set sampleBufferSize(int size) {
-    _sampleBufferSize = size;
-    _removeOld();
-  }
-
-  Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) {
+  Future<Map> _fetchDirect({int count: kDefaultFieldLimit}) {
     assert(owner is Isolate);
     return isolate.invokeRpcNoUpgrade('_getIsolateMetric', { 'metricId': id });
   }
 
-
-  void addSample(MetricSample sample) {
-    samples.add(sample);
-    _removeOld();
-  }
-
-  void _removeOld() {
-    // TODO(johnmccutchan): If this becomes hot, consider using a circular
-    // buffer.
-    if (samples.length > _sampleBufferSize) {
-      int count = samples.length - _sampleBufferSize;
-      samples.removeRange(0, count);
-    }
-  }
-
-  @observable String description;
-  @observable double value = 0.0;
+  String description;
+  double value = 0.0;
   // Only a guage has a non-null min and max.
-  @observable double min;
-  @observable double max;
+  double min;
+  double max;
 
   bool get isGauge => (min != null) && (max != null);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     name = map['name'];
     description = map['description'];
     vmName = map['name'];
@@ -4297,48 +4233,16 @@
   String toString() => "ServiceMetric($_id)";
 }
 
-class MetricPoller {
-  // Metrics to be polled.
-  final List<ServiceMetric> metrics = new List<ServiceMetric>();
-  final Duration pollPeriod;
-  Timer _pollTimer;
-
-  MetricPoller(int milliseconds) :
-      pollPeriod = new Duration(milliseconds: milliseconds) {
-    start();
-  }
-
-  void start() {
-    _pollTimer = new Timer.periodic(pollPeriod, _onPoll);
-  }
-
-  void cancel() {
-    if (_pollTimer != null) {
-      _pollTimer.cancel();
-    }
-    _pollTimer = null;
-  }
-
-  void _onPoll(_) {
-    // Reload metrics and add a sample to each.
-    for (var metric in metrics) {
-      metric.reload().then((m) {
-        m.addSample(new MetricSample(m.value));
-      });
-    }
-  }
-}
-
 class Frame extends ServiceObject implements M.Frame {
-  @observable int index;
-  @observable ServiceFunction function;
-  @observable SourceLocation location;
-  @observable Code code;
-  @observable List<ServiceMap> variables = new ObservableList<ServiceMap>();
+  int index;
+  ServiceFunction function;
+  SourceLocation location;
+  Code code;
+  List<ServiceMap> variables = <ServiceMap>[];
 
   Frame._empty(ServiceObject owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     assert(!mapIsRef);
     _loaded = true;
     _upgradeCollection(map, owner);
@@ -4354,15 +4258,15 @@
 
 
 class ServiceMessage extends ServiceObject {
-  @observable int index;
-  @observable String messageObjectId;
-  @observable int size;
-  @observable ServiceFunction handler;
-  @observable SourceLocation location;
+  int index;
+  String messageObjectId;
+  int size;
+  ServiceFunction handler;
+  SourceLocation location;
 
   ServiceMessage._empty(ServiceObject owner) : super._empty(owner);
 
-  void _update(ObservableMap map, bool mapIsRef) {
+  void _update(Map map, bool mapIsRef) {
     assert(!mapIsRef);
     _loaded = true;
     _upgradeCollection(map, owner);
@@ -4419,7 +4323,7 @@
 
 // Returns true if [map] is a service map. i.e. it has the following keys:
 // 'id' and a 'type'.
-bool _isServiceMap(ObservableMap m) {
+bool _isServiceMap(Map m) {
   return (m != null) && (m['type'] != null);
 }
 
@@ -4427,40 +4331,40 @@
 String _stripRef(String type) => (_hasRef(type) ? type.substring(1) : type);
 
 /// Recursively upgrades all [ServiceObject]s inside [collection] which must
-/// be an [ObservableMap] or an [ObservableList]. Upgraded elements will be
+/// be an [Map] or an [List]. Upgraded elements will be
 /// associated with [vm] and [isolate].
 void _upgradeCollection(collection, ServiceObjectOwner owner) {
   if (collection is ServiceMap) {
     return;
   }
-  if (collection is ObservableMap) {
-    _upgradeObservableMap(collection, owner);
-  } else if (collection is ObservableList) {
-    _upgradeObservableList(collection, owner);
+  if (collection is Map) {
+    _upgradeMap(collection, owner);
+  } else if (collection is List) {
+    _upgradeList(collection, owner);
   }
 }
 
-void _upgradeObservableMap(ObservableMap map, ServiceObjectOwner owner) {
+void _upgradeMap(Map map, ServiceObjectOwner owner) {
   map.forEach((k, v) {
-    if ((v is ObservableMap) && _isServiceMap(v)) {
+    if ((v is Map) && _isServiceMap(v)) {
       map[k] = owner.getFromMap(v);
-    } else if (v is ObservableList) {
-      _upgradeObservableList(v, owner);
-    } else if (v is ObservableMap) {
-      _upgradeObservableMap(v, owner);
+    } else if (v is List) {
+      _upgradeList(v, owner);
+    } else if (v is Map) {
+      _upgradeMap(v, owner);
     }
   });
 }
 
-void _upgradeObservableList(ObservableList list, ServiceObjectOwner owner) {
+void _upgradeList(List list, ServiceObjectOwner owner) {
   for (var i = 0; i < list.length; i++) {
     var v = list[i];
-    if ((v is ObservableMap) && _isServiceMap(v)) {
+    if ((v is Map) && _isServiceMap(v)) {
       list[i] = owner.getFromMap(v);
-    } else if (v is ObservableList) {
-      _upgradeObservableList(v, owner);
-    } else if (v is ObservableMap) {
-      _upgradeObservableMap(v, owner);
+    } else if (v is List) {
+      _upgradeList(v, owner);
+    } else if (v is Map) {
+      _upgradeMap(v, owner);
     }
   }
 }
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index 2f0291f..c139cd3 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -11,7 +11,6 @@
     'lib/cpu_profile.dart',
     'lib/debugger.dart',
     'lib/elements.dart',
-    'lib/elements.html',
     'lib/event.dart',
     'lib/heap_snapshot.dart',
     'lib/models.dart',
@@ -33,51 +32,38 @@
     'lib/src/cpu_profile/cpu_profile.dart',
     'lib/src/debugger/debugger.dart',
     'lib/src/debugger/debugger_location.dart',
-    'lib/src/elements/action_link.dart',
-    'lib/src/elements/action_link.html',
     'lib/src/elements/allocation_profile.dart',
     'lib/src/elements/class_allocation_profile.dart',
     'lib/src/elements/class_instances.dart',
     'lib/src/elements/class_ref.dart',
-    'lib/src/elements/class_ref_as_value.dart',
-    'lib/src/elements/class_ref_as_value.html',
-    'lib/src/elements/class_ref_wrapper.dart',
     'lib/src/elements/class_tree.dart',
     'lib/src/elements/class_view.dart',
     'lib/src/elements/code_ref.dart',
-    'lib/src/elements/code_ref_wrapper.dart',
     'lib/src/elements/code_view.dart',
     'lib/src/elements/containers/virtual_collection.dart',
     'lib/src/elements/containers/virtual_tree.dart',
     'lib/src/elements/context_ref.dart',
-    'lib/src/elements/context_ref_wrapper.dart',
     'lib/src/elements/context_view.dart',
     'lib/src/elements/cpu_profile.dart',
     'lib/src/elements/cpu_profile/virtual_tree.dart',
     'lib/src/elements/cpu_profile_table.dart',
     'lib/src/elements/css/shared.css',
     'lib/src/elements/curly_block.dart',
-    'lib/src/elements/curly_block_wrapper.dart',
     'lib/src/elements/debugger.dart',
-    'lib/src/elements/debugger.html',
     'lib/src/elements/error_ref.dart',
-    'lib/src/elements/error_ref_wrapper.dart',
     'lib/src/elements/error_view.dart',
     'lib/src/elements/eval_box.dart',
-    'lib/src/elements/eval_box_wrapper.dart',
-    'lib/src/elements/eval_link.dart',
-    'lib/src/elements/eval_link.html',
     'lib/src/elements/field_ref.dart',
-    'lib/src/elements/field_ref_wrapper.dart',
     'lib/src/elements/field_view.dart',
     'lib/src/elements/flag_list.dart',
     'lib/src/elements/function_ref.dart',
-    'lib/src/elements/function_ref_wrapper.dart',
     'lib/src/elements/function_view.dart',
     'lib/src/elements/general_error.dart',
     'lib/src/elements/heap_map.dart',
     'lib/src/elements/heap_snapshot.dart',
     'lib/src/elements/helpers/any_ref.dart',
+    'lib/src/elements/helpers/nav_bar.dart',
+    'lib/src/elements/helpers/nav_menu.dart',
     'lib/src/elements/helpers/rendering_queue.dart',
     'lib/src/elements/helpers/rendering_scheduler.dart',
     'lib/src/elements/helpers/tag.dart',
@@ -89,7 +75,6 @@
     'lib/src/elements/img/isolate_icon.png',
     'lib/src/elements/inbound_references.dart',
     'lib/src/elements/instance_ref.dart',
-    'lib/src/elements/instance_ref_wrapper.dart',
     'lib/src/elements/instance_view.dart',
     'lib/src/elements/isolate/counter_chart.dart',
     'lib/src/elements/isolate/location.dart',
@@ -98,69 +83,46 @@
     'lib/src/elements/isolate/summary.dart',
     'lib/src/elements/isolate_reconnect.dart',
     'lib/src/elements/isolate_ref.dart',
-    'lib/src/elements/isolate_ref_wrapper.dart',
     'lib/src/elements/isolate_view.dart',
     'lib/src/elements/json_view.dart',
     'lib/src/elements/library_ref.dart',
-    'lib/src/elements/library_ref_as_value.dart',
-    'lib/src/elements/library_ref_as_value.html',
-    'lib/src/elements/library_ref_wrapper.dart',
     'lib/src/elements/library_view.dart',
     'lib/src/elements/local_var_descriptors_ref.dart',
     'lib/src/elements/logging.dart',
     'lib/src/elements/logging_list.dart',
     'lib/src/elements/megamorphiccache_ref.dart',
     'lib/src/elements/megamorphiccache_view.dart',
+    'lib/src/elements/metric/details.dart',
+    'lib/src/elements/metric/graph.dart',
     'lib/src/elements/metrics.dart',
-    'lib/src/elements/metrics.html',
-    'lib/src/elements/nav/bar.dart',
     'lib/src/elements/nav/class_menu.dart',
-    'lib/src/elements/nav/class_menu_wrapper.dart',
     'lib/src/elements/nav/isolate_menu.dart',
-    'lib/src/elements/nav/isolate_menu_wrapper.dart',
     'lib/src/elements/nav/library_menu.dart',
-    'lib/src/elements/nav/library_menu_wrapper.dart',
-    'lib/src/elements/nav/menu.dart',
     'lib/src/elements/nav/menu_item.dart',
-    'lib/src/elements/nav/menu_item_wrapper.dart',
-    'lib/src/elements/nav/menu_wrapper.dart',
     'lib/src/elements/nav/notify.dart',
     'lib/src/elements/nav/notify_event.dart',
     'lib/src/elements/nav/notify_exception.dart',
-    'lib/src/elements/nav/notify_wrapper.dart',
     'lib/src/elements/nav/refresh.dart',
-    'lib/src/elements/nav/refresh_wrapper.dart',
     'lib/src/elements/nav/top_menu.dart',
-    'lib/src/elements/nav/top_menu_wrapper.dart',
     'lib/src/elements/nav/vm_menu.dart',
-    'lib/src/elements/nav/vm_menu_wrapper.dart',
     'lib/src/elements/object_common.dart',
-    'lib/src/elements/object_common_wrapper.dart',
     'lib/src/elements/object_view.dart',
     'lib/src/elements/objectpool_ref.dart',
     'lib/src/elements/objectpool_view.dart',
     'lib/src/elements/objectstore_view.dart',
     'lib/src/elements/observatory_application.dart',
-    'lib/src/elements/observatory_element.dart',
     'lib/src/elements/pc_descriptors_ref.dart',
     'lib/src/elements/persistent_handles.dart',
     'lib/src/elements/ports.dart',
     'lib/src/elements/retaining_path.dart',
     'lib/src/elements/sample_buffer_control.dart',
     'lib/src/elements/script_inset.dart',
-    'lib/src/elements/script_inset_wrapper.dart',
     'lib/src/elements/script_ref.dart',
-    'lib/src/elements/script_ref_wrapper.dart',
     'lib/src/elements/script_view.dart',
     'lib/src/elements/sentinel_value.dart',
     'lib/src/elements/sentinel_view.dart',
-    'lib/src/elements/service_ref.dart',
-    'lib/src/elements/service_ref.html',
-    'lib/src/elements/shims/binding.dart',
     'lib/src/elements/source_inset.dart',
-    'lib/src/elements/source_inset_wrapper.dart',
     'lib/src/elements/source_link.dart',
-    'lib/src/elements/source_link_wrapper.dart',
     'lib/src/elements/stack_trace_tree_config.dart',
     'lib/src/elements/strongly_reachable_instances.dart',
     'lib/src/elements/timeline_page.dart',
@@ -197,6 +159,7 @@
     'lib/src/models/objects/local_var_descriptors.dart',
     'lib/src/models/objects/map_association.dart',
     'lib/src/models/objects/megamorphiccache.dart',
+    'lib/src/models/objects/metric.dart',
     'lib/src/models/objects/notification.dart',
     'lib/src/models/objects/object.dart',
     'lib/src/models/objects/objectpool.dart',
@@ -231,6 +194,7 @@
     'lib/src/models/repositories/isolate.dart',
     'lib/src/models/repositories/library.dart',
     'lib/src/models/repositories/megamorphiccache.dart',
+    'lib/src/models/repositories/metric.dart',
     'lib/src/models/repositories/notification.dart',
     'lib/src/models/repositories/object.dart',
     'lib/src/models/repositories/objectpool.dart',
@@ -262,6 +226,7 @@
     'lib/src/repositories/isolate.dart',
     'lib/src/repositories/library.dart',
     'lib/src/repositories/megamorphiccache.dart',
+    'lib/src/repositories/metric.dart',
     'lib/src/repositories/notification.dart',
     'lib/src/repositories/object.dart',
     'lib/src/repositories/objectpool.dart',
diff --git a/runtime/observatory/pubspec.yaml b/runtime/observatory/pubspec.yaml
index e71be36..20f6ac4 100644
--- a/runtime/observatory/pubspec.yaml
+++ b/runtime/observatory/pubspec.yaml
@@ -2,25 +2,17 @@
 name: observatory
 version: 1.6.0-dev.1
 transformers:
-- polymer:
-    entry_points:
-    - web/index.html
-    inline_stylesheets:
-      lib/src/elements/css/shared.css: false
-      packages/charted/charts/themes/quantum_theme.css: false
-    $exclude: [web/third_party/*.html, web/timeline.html]
+- dart_to_js_script_rewriter
 - $dart2js:
-    $include: "**/*.polymer.bootstrap.dart"
     suppressWarnings: false
     commandLineOptions: [--show-package-warnings]
 dependencies:
   args: any
   charted: ^0.3.0
-  polymer: ^0.16.3
   unittest: < 0.12.0
-  js: ^0.6.0
-  js_util: ^0.2.0
   usage: any
+  web_components: any
+  dart_to_js_script_rewriter: any
 dependency_overrides:
   analyzer:
     path: ../../third_party/observatory_pub_packages/packages/analyzer
@@ -46,6 +38,8 @@
     path: ../../third_party/observatory_pub_packages/packages/csslib
   dart_style:
     path: ../../third_party/observatory_pub_packages/packages/dart_style
+  dart_to_js_script_rewriter:
+    path: ../../third_party/observatory_pub_packages/packages/dart_to_js_script_rewriter
   glob:
     path: ../../third_party/observatory_pub_packages/packages/glob
   html:
@@ -54,10 +48,6 @@
     path: ../../third_party/observatory_pub_packages/packages/initialize
   intl:
     path: ../../third_party/observatory_pub_packages/packages/intl
-  js:
-    path: ../../third_party/observatory_pub_packages/packages/js
-  js_util:
-    path: ../../third_party/observatory_pub_packages/packages/js_util
   logging:
     path: ../../third_party/observatory_pub_packages/packages/logging
   matcher:
@@ -72,12 +62,6 @@
     path: ../../third_party/observatory_pub_packages/packages/petitparser
   plugin:
     path: ../../third_party/observatory_pub_packages/packages/plugin
-  polymer:
-    path: ../../third_party/observatory_pub_packages/packages/polymer
-  polymer_expressions:
-    path: ../../third_party/observatory_pub_packages/packages/polymer_expressions
-  polymer_interop:
-    path: ../../third_party/observatory_pub_packages/packages/polymer_interop
   pool:
     path: ../../third_party/observatory_pub_packages/packages/pool
   quiver:
diff --git a/runtime/observatory/tests/observatory_ui/allocation_profile/element_test.html b/runtime/observatory/tests/observatory_ui/allocation_profile/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/allocation_profile/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/allocation_profile/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/class_ref/element_test.html b/runtime/observatory/tests/observatory_ui/class_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/class_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/class_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/class_tree/element_test.html b/runtime/observatory/tests/observatory_ui/class_tree/element_test.html
index 00d59bc..5efdf06 100644
--- a/runtime/observatory/tests/observatory_ui/class_tree/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/class_tree/element_test.html
@@ -15,7 +15,7 @@
        padding-right: 10%;
      }
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/code_ref/element_test.html b/runtime/observatory/tests/observatory_ui/code_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/code_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/code_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/context_ref/element_test.html b/runtime/observatory/tests/observatory_ui/context_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/context_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/context_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/context_view/element_test.html b/runtime/observatory/tests/observatory_ui/context_view/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/context_view/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/context_view/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/cpu_profile/element_test.html b/runtime/observatory/tests/observatory_ui/cpu_profile/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/cpu_profile/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/cpu_profile/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/cpu_profile/virtual-tree/element_test.html b/runtime/observatory/tests/observatory_ui/cpu_profile/virtual-tree/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/cpu_profile/virtual-tree/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/cpu_profile/virtual-tree/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html b/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart b/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart
index 139e235..54d50b9 100644
--- a/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart
@@ -69,19 +69,20 @@
   });
   test('elements created', () async {
     final e = new CurlyBlockElement();
-    expect(e.shadowRoot, isNotNull, reason: 'shadowRoot is created');
+    expect(e.children.length, isZero, reason: 'is empty');
     document.body.append(e);
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isNonZero,
-      reason: 'shadowRoot has elements');
+    expect(e.children.length, isNonZero,
+      reason: 'has elements');
     e.remove();
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isZero, reason: 'shadowRoot is empty');
+    expect(e.children.length, isZero, reason: 'is empty');
   });
   group('content', () {
     CurlyBlockElement e;
     setUp(() async {
       e = new CurlyBlockElement();
+      e.content = [document.createElement('content')];
       document.body.append(e);
       await e.onRendered.first;
     });
@@ -89,56 +90,56 @@
       e.remove();
     });
     test('toggles visibility', () async {
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.toggle();
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNotNull);
+      expect(e.querySelector('content'), isNotNull);
       e.toggle();
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.remove();
     });
     test('toggles visibility (manually)', () async {
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.expanded = true;
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNotNull);
+      expect(e.querySelector('content'), isNotNull);
       e.expanded = false;
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.remove();
     });
     test('does not toggle if disabled', () async {
       e.disabled = true;
       await e.onRendered.first;
       expect(e.expanded, isFalse);
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.toggle();
       await e.onRendered.first;
       expect(e.expanded, isFalse);
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.disabled = false;
       e.toggle();
       await e.onRendered.first;
       expect(e.expanded, isTrue);
-      expect(e.shadowRoot.querySelector('content'), isNotNull);
+      expect(e.querySelector('content'), isNotNull);
       e.disabled = true;
       e.toggle();
       await e.onRendered.first;
       expect(e.expanded, isTrue);
-      expect(e.shadowRoot.querySelector('content'), isNotNull);
+      expect(e.querySelector('content'), isNotNull);
       e.remove();
     });
     test('toggles visibility (manually) if disabled', () async {
       e.disabled = true;
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.expanded = true;
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNotNull);
+      expect(e.querySelector('content'), isNotNull);
       e.expanded = false;
       await e.onRendered.first;
-      expect(e.shadowRoot.querySelector('content'), isNull);
+      expect(e.querySelector('content'), isNull);
       e.remove();
     });
   });
diff --git a/runtime/observatory/tests/observatory_ui/curly_block/element_test.html b/runtime/observatory/tests/observatory_ui/curly_block/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/curly_block/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/curly_block/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/error_ref/element_test.html b/runtime/observatory/tests/observatory_ui/error_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/error_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/error_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/error_view/element_test.html b/runtime/observatory/tests/observatory_ui/error_view/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/error_view/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/error_view/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/field_ref/element_test.html b/runtime/observatory/tests/observatory_ui/field_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/field_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/field_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/flag_list/element_test.html b/runtime/observatory/tests/observatory_ui/flag_list/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/flag_list/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/flag_list/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/function_ref/element_test.html b/runtime/observatory/tests/observatory_ui/function_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/function_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/function_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/general_error/element_test.html b/runtime/observatory/tests/observatory_ui/general_error/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/general_error/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/general_error/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html b/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/icdata_ref/element_test.html b/runtime/observatory/tests/observatory_ui/icdata_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/icdata_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/icdata_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html b/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html b/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/instance_ref/element_test.html b/runtime/observatory/tests/observatory_ui/instance_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/instance_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/instance_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/isolate/counter_chart/element_test.html b/runtime/observatory/tests/observatory_ui/isolate/counter_chart/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/isolate/counter_chart/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/isolate/counter_chart/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/isolate/isolate-shared-summary/element_test.html b/runtime/observatory/tests/observatory_ui/isolate/isolate-shared-summary/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/isolate/isolate-shared-summary/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/isolate/isolate-shared-summary/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/isolate_reconnect/element_test.html b/runtime/observatory/tests/observatory_ui/isolate_reconnect/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/isolate_reconnect/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/isolate_reconnect/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html b/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/isolate_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/library_ref/element_test.html b/runtime/observatory/tests/observatory_ui/library_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/library_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/library_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/local_var_descriptor_ref/element_test.html b/runtime/observatory/tests/observatory_ui/local_var_descriptor_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/local_var_descriptor_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/local_var_descriptor_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/megamorphiccache_ref/element_test.html b/runtime/observatory/tests/observatory_ui/megamorphiccache_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/megamorphiccache_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/megamorphiccache_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/megamorphiccache_view/element_test.html b/runtime/observatory/tests/observatory_ui/megamorphiccache_view/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/megamorphiccache_view/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/megamorphiccache_view/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/bar/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/bar/element_test.dart
deleted file mode 100644
index e450d3e..0000000
--- a/runtime/observatory/tests/observatory_ui/nav/bar/element_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'package:unittest/unittest.dart';
-import 'package:observatory/src/elements/nav/bar.dart';
-
-main() {
-  NavBarElement.tag.ensureRegistration();
-
-  test('instantiation', () {
-    final e = new NavBarElement();
-    expect(e, isNotNull, reason: 'element correctly created');
-  });
-  test('elements created', () async {
-    final e = new NavBarElement();
-    document.body.append(e);
-    await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
-    expect(e.shadowRoot.querySelector('content'), isNotNull,
-                                               reason: 'has content elements');
-    e.remove();
-    await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
-  });
-}
diff --git a/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart
index 32fb9f0..c622dbe 100644
--- a/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart
@@ -20,11 +20,12 @@
   });
   test('elements created after attachment', () async {
     final e = new NavClassMenuElement(i_ref, c_ref);
+    e.content = [document.createElement('content')];
     document.body.append(e);
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+    expect(e.children.length, isNonZero, reason: 'has elements');
     e.remove();
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+    expect(e.children.length, isZero, reason: 'is empty');
   });
 }
diff --git a/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart
index 3241c45..5d40f27 100644
--- a/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart
@@ -4,14 +4,13 @@
 
 import 'dart:html';
 import 'package:unittest/unittest.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/isolate_menu.dart';
 import '../../mocks.dart';
 
 main() {
   NavIsolateMenuElement.tag.ensureRegistration();
 
-  final tag = NavMenuElement.tag.name;
+  final tag = '.nav-menu_label > a';
 
   EventRepositoryMock events;
   final ref = const IsolateRefMock(id: 'i-id', name: 'old-name');
@@ -35,10 +34,10 @@
     final e = new NavIsolateMenuElement(ref, events);
     document.body.append(e);
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+    expect(e.children.length, isNonZero, reason: 'has elements');
     e.remove();
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+    expect(e.children.length, isZero, reason: 'is empty');
   });
   group('updates', () {
     test('are correctly listen', () async {
@@ -55,14 +54,11 @@
       final e = new NavIsolateMenuElement(ref, events);
       document.body.append(e);
       await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(tag) as NavMenuElement)
-             .label.contains(ref.name), isTrue);
+      expect(e.querySelector(tag).text.contains(ref.name), isTrue);
       events.add(new IsolateUpdateEventMock(isolate: obj));
       await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(tag) as NavMenuElement)
-             .label.contains(ref.name), isFalse);
-      expect((e.shadowRoot.querySelector(tag) as NavMenuElement)
-            .label.contains(obj.name), isTrue);
+      expect(e.querySelector(tag).text.contains(ref.name), isFalse);
+      expect(e.querySelector(tag).text.contains(obj.name), isTrue);
       e.remove();
     });
   });
diff --git a/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart
index 86fecea..c566588 100644
--- a/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart
@@ -22,9 +22,9 @@
     final e = new NavLibraryMenuElement(i_ref, l_ref);
     document.body.append(e);
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+    expect(e.children.length, isNonZero, reason: 'has elements');
     e.remove();
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+    expect(e.children.length, isZero, reason: 'is empty');
   });
 }
diff --git a/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart
index 5ab71f1..779cd0a 100644
--- a/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart
@@ -27,14 +27,15 @@
     test('created', () async {
       final label = 'custom-label';
       final e = new NavMenuItemElement(label);
+      e.content = [document.createElement('content')];
       document.body.append(e);
       await e.onRendered.first;
-      expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
-      expect(e.shadowRoot.querySelector('content'), isNotNull,
+      expect(e.children.length, isNonZero, reason: 'has elements');
+      expect(e.querySelector('content'), isNotNull,
                                                  reason: 'has content elements');
       e.remove();
       await e.onRendered.first;
-      expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+      expect(e.children.length, isZero, reason: 'is empty');
     });
     test('react to label change', () async {
       final label1 = 'custom-label-1';
@@ -42,12 +43,12 @@
       final e = new NavMenuItemElement(label1);
       document.body.append(e);
       await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains(label1), isTrue);
-      expect(e.shadowRoot.innerHtml.contains(label2), isFalse);
+      expect(e.innerHtml.contains(label1), isTrue);
+      expect(e.innerHtml.contains(label2), isFalse);
       e.label = label2;
       await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains(label1), isFalse);
-      expect(e.shadowRoot.innerHtml.contains(label2), isTrue);
+      expect(e.innerHtml.contains(label1), isFalse);
+      expect(e.innerHtml.contains(label2), isTrue);
       e.remove();
       await e.onRendered.first;
     });
@@ -58,12 +59,12 @@
       final e = new NavMenuItemElement(label, link: link1);
       document.body.append(e);
       await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains(link1), isTrue);
-      expect(e.shadowRoot.innerHtml.contains(link2), isFalse);
+      expect(e.innerHtml.contains(link1), isTrue);
+      expect(e.innerHtml.contains(link2), isFalse);
       e.link = link2;
       await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains(link1), isFalse);
-      expect(e.shadowRoot.innerHtml.contains(link2), isTrue);
+      expect(e.innerHtml.contains(link1), isFalse);
+      expect(e.innerHtml.contains(link2), isTrue);
       e.remove();
       await e.onRendered.first;
     });
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/menu/element_test.dart
deleted file mode 100644
index 5b35836..0000000
--- a/runtime/observatory/tests/observatory_ui/nav/menu/element_test.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'package:unittest/unittest.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
-
-main() {
-  NavMenuElement.tag.ensureRegistration();
-
-  group('instantiation', () {
-    final label = 'custom-label';
-    test('label', () {
-      final e = new NavMenuElement(label);
-      expect(e, isNotNull, reason: 'element correctly created');
-      expect(e.label, equals(label), reason: 'element correctly created');
-    });
-    test('not last', () {
-      final e = new NavMenuElement(label, last: false);
-      expect(e, isNotNull, reason: 'element correctly created');
-      expect(e.last, isFalse, reason: 'element correctly created');
-    });
-    test('last', () {
-      final e = new NavMenuElement(label, last: true);
-      expect(e, isNotNull, reason: 'element correctly created');
-      expect(e.last, isTrue, reason: 'element correctly created');
-    });
-  });
-  group('elements', () {
-    test('created', () async {
-      final label = 'custom-label';
-      final e = new NavMenuElement(label);
-      document.body.append(e);
-      await e.onRendered.first;
-      expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
-      expect(e.shadowRoot.querySelector('content'), isNotNull,
-                                                 reason: 'has content elements');
-      e.remove();
-      await e.onRendered.first;
-      expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
-    });
-    test('react to label change', () async {
-      final label1 = 'custom-label-1';
-      final label2 = 'custom-label-2';
-      final e = new NavMenuElement(label1);
-      document.body.append(e);
-      await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains(label1), isTrue);
-      expect(e.shadowRoot.innerHtml.contains(label2), isFalse);
-      e.label = label2;
-      await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains(label1), isFalse);
-      expect(e.shadowRoot.innerHtml.contains(label2), isTrue);
-      e.remove();
-      await e.onRendered.first;
-    });
-    test('react to last change', () async {
-      final label = 'custom-label';
-      final e = new NavMenuElement(label, last: false);
-      document.body.append(e);
-      await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains('&gt;'), isTrue);
-      e.last = true;
-      await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains('&gt;'), isFalse);
-      e.last = false;
-      await e.onRendered.first;
-      expect(e.shadowRoot.innerHtml.contains('&gt;'), isTrue);
-      e.remove();
-      await e.onRendered.first;
-    });
-  });
-}
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/menu/element_test.html
deleted file mode 100644
index f0e956d..0000000
--- a/runtime/observatory/tests/observatory_ui/nav/menu/element_test.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <meta http-equiv="X-UA-Compatible" content="IE=edge">
-  <meta name="dart.unittest" content="full-stack-traces">
-  <style>
-     .unittest-table { font-family:monospace; border:1px; }
-     .unittest-pass { background: #6b3;}
-     .unittest-fail { background: #d55;}
-     .unittest-error { background: #a11;}
-  </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
-  <script src="/packages/web_components/dart_support.js"></script>
-</head>
-<body>
-  <script type="text/javascript"
-      src="/root_dart/tools/testing/dart/test_controller.js"></script>
-  %TEST_SCRIPTS%
-</body>
-</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html b/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html b/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html b/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html b/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html b/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.dart
deleted file mode 100644
index 8a161b6..0000000
--- a/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:html';
-import 'package:unittest/unittest.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
-import 'package:observatory/src/elements/nav/top_menu.dart';
-
-main() {
-  NavTopMenuElement.tag.ensureRegistration();
-
-  final tag = NavMenuElement.tag.name;
-
-  group('instantiation', () {
-    test('default', () {
-      final e = new NavTopMenuElement();
-      expect(e, isNotNull, reason: 'element correctly created');
-    });
-    test('not last', () {
-      final e = new NavTopMenuElement(last: false);
-      expect(e, isNotNull, reason: 'element correctly created');
-      expect(e.last, isFalse, reason: 'element correctly created');
-    });
-    test('last', () {
-      final e = new NavTopMenuElement(last: true);
-      expect(e, isNotNull, reason: 'element correctly created');
-      expect(e.last, isTrue, reason: 'element correctly created');
-    });
-  });
-  group('elements', () {
-    test('created', () async {
-      final e = new NavTopMenuElement();
-      document.body.append(e);
-      await e.onRendered.first;
-      expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
-      expect(e.shadowRoot.querySelector('content'), isNotNull,
-                                                 reason: 'has content elements');
-      e.remove();
-      await e.onRendered.first;
-      expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
-    });
-    test('react to last change', () async {
-      final e = new NavTopMenuElement(last: false);
-      document.body.append(e);
-      await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(tag) as NavMenuElement).last, isFalse);
-      e.last = true;
-      await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(tag) as NavMenuElement).last, isTrue);
-      e.last = false;
-      await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(tag) as NavMenuElement).last, isFalse);
-      e.remove();
-      await e.onRendered.first;
-    });
-  });
-}
diff --git a/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.html
deleted file mode 100644
index f0e956d..0000000
--- a/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <meta http-equiv="X-UA-Compatible" content="IE=edge">
-  <meta name="dart.unittest" content="full-stack-traces">
-  <style>
-     .unittest-table { font-family:monospace; border:1px; }
-     .unittest-pass { background: #6b3;}
-     .unittest-fail { background: #d55;}
-     .unittest-error { background: #a11;}
-  </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
-  <script src="/packages/web_components/dart_support.js"></script>
-</head>
-<body>
-  <script type="text/javascript"
-      src="/root_dart/tools/testing/dart/test_controller.js"></script>
-  %TEST_SCRIPTS%
-</body>
-</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/top_menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/top_menu/element_test.dart
new file mode 100644
index 0000000..31afda2
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/top_menu/element_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+
+main() {
+  NavTopMenuElement.tag.ensureRegistration();
+
+  test('instantiation', () {
+    final e = new NavTopMenuElement();
+    expect(e, isNotNull, reason: 'element correctly created');
+  });
+  group('elements', () {
+    test('created', () async {
+      final e = new NavTopMenuElement();
+      e.content = [document.createElement('content')];
+      document.body.append(e);
+      await e.onRendered.first;
+      expect(e.children.length, isNonZero, reason: 'has elements');
+      expect(e.querySelector('content'), isNotNull,
+                                                 reason: 'has content elements');
+      e.remove();
+      await e.onRendered.first;
+      expect(e.children.length, isZero, reason: 'is empty');
+    });
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/bar/element_test.html b/runtime/observatory/tests/observatory_ui/nav/top_menu/element_test.html
similarity index 87%
rename from runtime/observatory/tests/observatory_ui/nav/bar/element_test.html
rename to runtime/observatory/tests/observatory_ui/nav/top_menu/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/bar/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/top_menu/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart
index a5596a7..0333689 100644
--- a/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart
@@ -4,7 +4,6 @@
 
 import 'dart:html';
 import 'package:unittest/unittest.dart';
-import 'package:observatory/src/elements/nav/menu.dart';
 import 'package:observatory/src/elements/nav/menu_item.dart';
 import 'package:observatory/src/elements/nav/vm_menu.dart';
 import '../../mocks.dart';
@@ -12,7 +11,7 @@
 main(){
   NavVMMenuElement.tag.ensureRegistration();
 
-  final mTag = NavMenuElement.tag.name;
+  final mTag = '.nav-menu_label > a';
   final miTag = NavMenuItemElement.tag.name;
 
   EventRepositoryMock events;
@@ -33,10 +32,10 @@
     final e = new NavVMMenuElement(vm1, events);
     document.body.append(e);
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+    expect(e.children.length, isNonZero, reason: 'has elements');
     e.remove();
     await e.onRendered.first;
-    expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+    expect(e.children.length, isZero, reason: 'is empty');
   });
   group('updates', () {
     test('are correctly listen', () async {
@@ -53,15 +52,13 @@
       final e = new NavVMMenuElement(vm1, events);
       document.body.append(e);
       await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(mTag) as NavMenuElement).label,
-          equals(vm1.displayName));
-      expect(e.shadowRoot.querySelectorAll(miTag).length,
+      expect(e.querySelectorAll(mTag).single.text, equals(vm1.displayName));
+      expect(e.querySelectorAll(miTag).length,
           equals(vm1.isolates.length));
       events.add(new VMUpdateEventMock(vm: vm2));
       await e.onRendered.first;
-      expect((e.shadowRoot.querySelector(mTag) as NavMenuElement).label,
-          equals(vm2.displayName));
-      expect(e.shadowRoot.querySelectorAll(miTag).length,
+      expect(e.querySelectorAll(mTag).single.text, equals(vm2.displayName));
+      expect(e.querySelectorAll(miTag).length,
           equals(vm2.isolates.length));
       e.remove();
     });
diff --git a/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/object_common/element_test.html b/runtime/observatory/tests/observatory_ui/object_common/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/object_common/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/object_common/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/objectpool_ref/element_test.html b/runtime/observatory/tests/observatory_ui/objectpool_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/objectpool_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/objectpool_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/objectpool_view/element_test.html b/runtime/observatory/tests/observatory_ui/objectpool_view/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/objectpool_view/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/objectpool_view/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/objectstore_view/element_test.html b/runtime/observatory/tests/observatory_ui/objectstore_view/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/objectstore_view/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/objectstore_view/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.html b/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/persistent_handles_page/element_test.html b/runtime/observatory/tests/observatory_ui/persistent_handles_page/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/persistent_handles_page/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/persistent_handles_page/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/ports/element_test.html b/runtime/observatory/tests/observatory_ui/ports/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/ports/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/ports/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html b/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/sample_buffer_control/element_test.html b/runtime/observatory/tests/observatory_ui/sample_buffer_control/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/sample_buffer_control/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/sample_buffer_control/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/script_ref/element_test.html b/runtime/observatory/tests/observatory_ui/script_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/script_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/script_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/sentinel_value/element_test.html b/runtime/observatory/tests/observatory_ui/sentinel_value/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/sentinel_value/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/sentinel_value/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/source_link/element_test.html b/runtime/observatory/tests/observatory_ui/source_link/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/source_link/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/source_link/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/stack_trace_tree_config/element_test.html b/runtime/observatory/tests/observatory_ui/stack_trace_tree_config/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/stack_trace_tree_config/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/stack_trace_tree_config/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/token_stream_ref/element_test.html b/runtime/observatory/tests/observatory_ui/token_stream_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/token_stream_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/token_stream_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/unknown_ref/element_test.html b/runtime/observatory/tests/observatory_ui/unknown_ref/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/unknown_ref/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/unknown_ref/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/view_footer/element_test.html b/runtime/observatory/tests/observatory_ui/view_footer/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/view_footer/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/view_footer/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/vm_connect/element_test.html b/runtime/observatory/tests/observatory_ui/vm_connect/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/vm_connect/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/vm_connect/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html b/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html
index f0e956d..68d7761 100644
--- a/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html
+++ b/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html
@@ -9,7 +9,7 @@
      .unittest-fail { background: #d55;}
      .unittest-error { background: #a11;}
   </style>
-  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/webcomponents-lite.min.js"></script>
   <script src="/packages/web_components/dart_support.js"></script>
 </head>
 <body>
diff --git a/runtime/observatory/web/index.html b/runtime/observatory/web/index.html
index ccd9bfc..db0a85e 100644
--- a/runtime/observatory/web/index.html
+++ b/runtime/observatory/web/index.html
@@ -3,13 +3,12 @@
 <head>
   <meta charset="utf-8">
   <title>Dart VM Observatory</title>
-  <link rel="import" href="packages/polymer/polymer.html">
   <link rel="stylesheet" href="packages/charted/charts/themes/quantum_theme.css">
   <link rel="stylesheet" href="packages/observatory/src/elements/css/shared.css">
-  <link rel="import" href="packages/observatory/elements.html">
-  <script src="packages/js_util/dist/js_util.js"></script>
-  <script type="application/dart" src="main.dart"></script>
-  <script src="packages/browser/dart.js"></script>
+  <script src="packages/web_components/webcomponents-lite.min.js"></script>
+  <script src="packages/web_components/dart_support.js"></script>
+  <script async type="application/dart" src="main.dart"></script>
+  <script async src="packages/browser/dart.js"></script>
 </head>
 <body style="height: 100%">
 </body>
diff --git a/runtime/observatory/web/main.dart b/runtime/observatory/web/main.dart
index 36c03ab..4f63d25 100644
--- a/runtime/observatory/web/main.dart
+++ b/runtime/observatory/web/main.dart
@@ -4,27 +4,15 @@
 
 import 'dart:html';
 import 'package:logging/logging.dart';
-import 'package:polymer/polymer.dart';
 import 'package:observatory/elements.dart';
 
 main() async {
   Logger.root.level = Level.INFO;
   Logger.root.onRecord.listen((LogRecord rec) {
-      if (rec.level == Level.WARNING &&
-          rec.message.startsWith('Error evaluating expression') &&
-          (rec.message.contains("Can't assign to null: ") ||
-           rec.message.contains('Expression is not assignable: '))) {
-        // Suppress flaky polymer errors.
-        return;
-      }
       print('${rec.level.name}: ${rec.time}: ${rec.message}');
   });
   await initElements();
   Logger.root.info('Starting Observatory');
-  await initPolymer();
-  Logger.root.info('Polymer initialized');
-  await Polymer.onReady;
-  Logger.root.info('Polymer elements have been upgraded');
   document.body.children
       .insert(0, document.createElement('observatory-application'));
 }
diff --git a/runtime/platform/assert.cc b/runtime/platform/assert.cc
index 921a564..000546a 100644
--- a/runtime/platform/assert.cc
+++ b/runtime/platform/assert.cc
@@ -10,10 +10,7 @@
 
 namespace dart {
 
-// Exit with a failure code when we miss an EXPECT check.
-static void failed_exit(void) {
-  exit(255);
-}
+bool DynamicAssertionHelper::failed_ = false;
 
 void DynamicAssertionHelper::Fail(const char* format, ...) {
   // Take only the last 1KB of the file name if it is longer.
@@ -45,11 +42,7 @@
     NOT_IN_PRODUCT(Profiler::DumpStackTrace(true /* native_stack_trace */));
     OS::Abort();
   }
-  static bool failed = false;
-  if (!failed) {
-    atexit(&failed_exit);
-  }
-  failed = true;
+  failed_ = true;
 }
 
 }  // namespace dart
diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h
index 9d6d67c..0e8969c 100644
--- a/runtime/platform/assert.h
+++ b/runtime/platform/assert.h
@@ -35,6 +35,8 @@
 
   void Fail(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
 
+  static bool failed() { return failed_; }
+
 #if defined(TESTING)
   template<typename E, typename A>
   void Equals(const E& expected, const A& actual);
@@ -71,6 +73,8 @@
   T NotNull(const T p);
 
  private:
+  static bool failed_;
+
   const char* const file_;
   const int line_;
   const Kind kind_;
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 2dc0be48a..208a224 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -37,6 +37,8 @@
 #define I (isolate())
 #define Z (zone())
 
+#ifdef DART_PRECOMPILER
+
 static bool ShouldInlineSimd() {
   return FlowGraphCompiler::SupportsUnboxedSimd128();
 }
@@ -1521,10 +1523,7 @@
 
   if (TypeCheckAsClassEquality(type)) {
     LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left));
-    InsertBefore(call,
-                 left_cid,
-                 NULL,
-                 FlowGraph::kValue);
+    InsertBefore(call, left_cid, NULL, FlowGraph::kValue);
     const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
     ConstantInstr* cid =
         flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));
@@ -1540,6 +1539,51 @@
     return;
   }
 
+  TypeRangeCache* cache = thread()->type_range_cache();
+  intptr_t lower_limit, upper_limit;
+  if (cache != NULL &&
+      cache->InstanceOfHasClassRange(type, &lower_limit, &upper_limit)) {
+    // left.instanceof(type) =>
+    //     _classRangeCheck(left.cid, lower_limit, upper_limit)
+
+    LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left));
+    InsertBefore(call, left_cid, NULL, FlowGraph::kValue);
+    ConstantInstr* lower_cid =
+        flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(lower_limit)));
+    ConstantInstr* upper_cid =
+        flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(upper_limit)));
+
+    ZoneGrowableArray<PushArgumentInstr*>* args =
+        new(Z) ZoneGrowableArray<PushArgumentInstr*>(3);
+    PushArgumentInstr* arg = new (Z) PushArgumentInstr(new (Z) Value(left_cid));
+    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
+    args->Add(arg);
+    arg = new (Z) PushArgumentInstr(new (Z) Value(lower_cid));
+    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
+    args->Add(arg);
+    arg = new (Z) PushArgumentInstr(new (Z) Value(upper_cid));
+    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
+    args->Add(arg);
+
+    const Library& dart_internal =
+        Library::Handle(Z, Library::InternalLibrary());
+    const String& target_name = negate ? Symbols::_classRangeCheckNegative()
+                                       : Symbols::_classRangeCheck();
+    const Function& target = Function::ZoneHandle(Z,
+        dart_internal.LookupFunctionAllowPrivate(target_name));
+    ASSERT(!target.IsNull());
+    ASSERT(target.IsRecognized() && target.always_inline());
+
+    StaticCallInstr* new_call = new (Z) StaticCallInstr(
+        call->token_pos(),
+        target,
+        Object::null_array(),  // argument_names
+        args,
+        call->deopt_id());
+    ReplaceCall(call, new_call);
+    return;
+  }
+
   const ICData& unary_checks =
       ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
   if ((unary_checks.NumberOfChecks() > 0) &&
@@ -2138,5 +2182,6 @@
   }
 }
 
+#endif  // DART_PRECOMPILER
 
 }  // namespace dart
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
index 972a71c..f35536c 100644
--- a/runtime/vm/aot_optimizer.h
+++ b/runtime/vm/aot_optimizer.h
@@ -106,7 +106,6 @@
 
   void ReplaceCall(Definition* call, Definition* replacement);
 
-
   bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
                                    RawFunction::Kind kind) const;
 
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 0601dae..8ddbd39 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -4968,11 +4968,14 @@
 
     OS::Print("VMIsolate(CodeSize): %" Pd "\n", VmIsolateSnapshotSize());
     OS::Print("Isolate(CodeSize): %" Pd "\n", IsolateSnapshotSize());
+    OS::Print("ReadOnlyData(CodeSize): %" Pd "\n",
+              instructions_writer_->data_size());
     OS::Print("Instructions(CodeSize): %" Pd "\n",
-              instructions_writer_->binary_size());
+              instructions_writer_->text_size());
     intptr_t total = VmIsolateSnapshotSize() +
                      IsolateSnapshotSize() +
-                     instructions_writer_->binary_size();
+                     instructions_writer_->data_size() +
+                     instructions_writer_->text_size();
     OS::Print("Total(CodeSize): %" Pd "\n", total);
   }
 }
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 4fee793..3293a18 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -691,7 +691,7 @@
     if (val == 0) {
       FlowGraph* flow_graph = NULL;
 
-      // Class hierarchy analysis is registered with the isolate in the
+      // Class hierarchy analysis is registered with the thread in the
       // constructor and unregisters itself upon destruction.
       CHA cha(thread());
 
@@ -1377,7 +1377,7 @@
                                     const Function& function) {
 #ifdef DART_PRECOMPILER
   if (FLAG_precompiled_mode) {
-    return Precompiler::CompileFunction(thread, function);
+    return Precompiler::CompileFunction(thread, thread->zone(), function);
   }
 #endif
   Isolate* isolate = thread->isolate();
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 8367316..e668652 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -62,6 +62,7 @@
 DECLARE_FLAG(int, inlining_constant_arguments_max_size_threshold);
 DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
 DECLARE_FLAG(int, reload_every);
+DECLARE_FLAG(bool, unbox_numeric_fields);
 
 static void PrecompilationModeHandler(bool value) {
   if (value) {
@@ -94,6 +95,7 @@
     FLAG_reorder_basic_blocks = false;
     FLAG_use_field_guards = false;
     FLAG_use_cha_deopt = false;
+    FLAG_unbox_numeric_fields = false;
 
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
     // Set flags affecting runtime accordingly for dart_noopt.
@@ -1144,7 +1146,8 @@
           *return_node.value()->AsLoadInstanceFieldNode();
       // Only intrinsify getter if the field cannot contain a mutable double.
       // Reading from a mutable double box requires allocating a fresh double.
-      if (!IsPotentialUnboxedField(load_node.field())) {
+      if (FLAG_precompiled_mode ||
+          !IsPotentialUnboxedField(load_node.field())) {
         GenerateInlinedGetter(load_node.field().Offset());
         return !FLAG_use_field_guards;
       }
@@ -1159,7 +1162,8 @@
       ASSERT(sequence_node.NodeAt(1)->IsReturnNode());
       const StoreInstanceFieldNode& store_node =
           *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
-      if (store_node.field().guarded_cid() == kDynamicCid) {
+      if (FLAG_precompiled_mode ||
+          (store_node.field().guarded_cid() == kDynamicCid)) {
         GenerateInlinedSetter(store_node.field().Offset());
         return !FLAG_use_field_guards;
       }
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 7541f1b..d6c74cb 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -705,9 +705,6 @@
                                                    Label* is_instance_lbl,
                                                    Label* is_not_instance_lbl);
 
-  // Returns true if checking against this type is a direct class id comparison.
-  bool TypeCheckAsClassEquality(const AbstractType& type);
-
   void GenerateBoolToJump(Register bool_reg, Label* is_true, Label* is_false);
 
   void CopyParameters();
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index d694263..113c3e9 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -362,7 +362,7 @@
               current->AsPolymorphicInstanceCall();
           if (!inline_only_recognized_methods ||
               instance_call->HasSingleRecognizedTarget() ||
-              instance_call->HasOnlyDispatcherTargets()) {
+              instance_call->ic_data().HasOnlyDispatcherTargets()) {
             instance_calls_.Add(InstanceCallInfo(instance_call, graph));
           } else {
             // Method not inlined because inlining too deep and method
@@ -828,6 +828,7 @@
           // TODO(fschneider): Improve suppression of speculative inlining.
           // Deopt-ids overlap between caller and callee.
           if (FLAG_precompiled_mode) {
+#ifdef DART_PRECOMPILER
             AotOptimizer optimizer(callee_graph,
                                    inliner_->use_speculative_inlining_,
                                    inliner_->inlining_black_list_);
@@ -846,6 +847,9 @@
             // before 'SelectRepresentations' which inserts conversion nodes.
             callee_graph->TryOptimizePatterns();
             DEBUG_ASSERT(callee_graph->VerifyUseLists());
+#else
+            UNREACHABLE();
+#endif  // DART_PRECOMPILER
           } else {
             JitOptimizer optimizer(callee_graph);
 
diff --git a/runtime/vm/handles_impl.h b/runtime/vm/handles_impl.h
index 635c2db..bf44e63 100644
--- a/runtime/vm/handles_impl.h
+++ b/runtime/vm/handles_impl.h
@@ -93,7 +93,6 @@
               kOffsetOfRawPtr>::AllocateHandle(Zone* zone) {
 #if defined(DEBUG)
   Thread* thread = Thread::Current();
-  ASSERT(thread->zone() == zone);
   ASSERT(thread->top_handle_scope() != NULL);
   ASSERT(thread->no_handle_scope_depth() == 0);
 #endif  // DEBUG
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 372ff7f..64f8790 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -168,13 +168,14 @@
 template<typename KeyValueTrait, typename B, typename Allocator>
 typename KeyValueTrait::Pair*
     BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() {
-  const typename KeyValueTrait::Pair kNoPair = typename KeyValueTrait::Pair();
+  const typename KeyValueTrait::Value kNoValue =
+      KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
 
   if (array_index_ < map_.array_size_) {
     // If we're not in the middle of a list, find the next array slot.
     if (list_index_ == kNil) {
-      while ((map_.array_[array_index_].kv == kNoPair) &&
-             (array_index_ < map_.array_size_)) {
+      while (KeyValueTrait::ValueOf(map_.array_[array_index_].kv) == kNoValue &&
+             array_index_ < map_.array_size_) {
         array_index_++;
       }
       if (array_index_ < map_.array_size_) {
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 20b876e..ab7c878 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -3188,6 +3188,8 @@
 
 
 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const {
+  if (FLAG_precompiled_mode && with_checks()) return false;
+
   return ic_data().HasOneTarget() &&
       (MethodRecognizer::RecognizeKind(
           Function::Handle(ic_data().GetTargetAt(0))) !=
@@ -3195,18 +3197,6 @@
 }
 
 
-bool PolymorphicInstanceCallInstr::HasOnlyDispatcherTargets() const {
-  for (intptr_t i = 0; i < ic_data().NumberOfChecks(); ++i) {
-    const Function& target = Function::Handle(ic_data().GetTargetAt(i));
-    if (!target.IsNoSuchMethodDispatcher() &&
-        !target.IsInvokeFieldDispatcher()) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
 // DBC does not support optimizing compiler and thus doesn't emit
 // PolymorphicInstanceCallInstr.
 #if !defined(TARGET_ARCH_DBC)
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 7793391..3a5ab03 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -2923,8 +2923,6 @@
 
   bool HasSingleRecognizedTarget() const;
 
-  bool HasOnlyDispatcherTargets() const;
-
   virtual intptr_t CallCount() const { return ic_data().AggregateCount(); }
 
   DECLARE_INSTRUCTION(PolymorphicInstanceCall)
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 9adb042..651ee3c 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -128,6 +128,8 @@
     0x306e6a79)                                                                \
   V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, Dynamic,      \
     0x3fe95fc2)                                                                \
+  V(::, _classRangeCheck, ClassRangeCheck, Bool, 0x6279a7b3)                   \
+  V(::, _classRangeCheckNegative, ClassRangeCheckNegated, Bool, 0x4799dac1)    \
 
 
 // List of intrinsics:
@@ -403,6 +405,8 @@
   V(::, max, MathMax, 0x54121d6a)                                              \
   V(::, min, MathMin, 0x4276561c)                                              \
   V(::, pow, MathPow, 0x438e3089)                                              \
+  V(::, _classRangeCheck, ClassRangeCheck, 0x6279a7b3)                         \
+  V(::, _classRangeCheckNegative, ClassRangeCheckNegated, 0x4799dac1)          \
   V(Lists, copy, ListsCopy, 0x21a194fa)                                        \
   V(_Bigint, get:_neg, Bigint_getNeg, 0x7bf17a57)                              \
   V(_Bigint, get:_used, Bigint_getUsed, 0x55041013)                            \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index b78a452..3af1f36 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7476,13 +7476,14 @@
   // Use field guards if they are enabled and the isolate has never reloaded.
   // TODO(johnmccutchan): The reload case assumes the worst case (everything is
   // dynamic and possibly null). Attempt to relax this later.
-  const bool use_field_guards =
-      FLAG_use_field_guards && !isolate->HasAttemptedReload();
-  result.set_guarded_cid(use_field_guards ? kIllegalCid : kDynamicCid);
-  result.set_is_nullable(use_field_guards ? false : true);
+  const bool use_guarded_cid =
+      FLAG_precompiled_mode ||
+      (FLAG_use_field_guards && !isolate->HasAttemptedReload());
+  result.set_guarded_cid(use_guarded_cid ? kIllegalCid : kDynamicCid);
+  result.set_is_nullable(use_guarded_cid ? false : true);
   result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
   // Presently, we only attempt to remember the list length for final fields.
-  if (is_final && use_field_guards) {
+  if (is_final && use_guarded_cid) {
     result.set_guarded_list_length(Field::kUnknownFixedLength);
   } else {
     result.set_guarded_list_length(Field::kNoFixedLength);
@@ -11402,6 +11403,7 @@
   all_libs.Add(&Library::ZoneHandle(Library::MathLibrary()));
   all_libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
   all_libs.Add(&Library::ZoneHandle(Library::CollectionLibrary()));
+  all_libs.Add(&Library::ZoneHandle(Library::InternalLibrary()));
   OTHER_RECOGNIZED_LIST(CHECK_FINGERPRINTS2);
   INLINE_WHITE_LIST(CHECK_FINGERPRINTS);
   INLINE_BLACK_LIST(CHECK_FINGERPRINTS);
@@ -13411,6 +13413,20 @@
 }
 
 
+bool ICData::HasOnlyDispatcherTargets() const {
+  const intptr_t len = NumberOfChecks();
+  Function& target = Function::Handle();
+  for (intptr_t i = 0; i < len; i++) {
+    target = GetTargetAt(i);
+    if (!target.IsNoSuchMethodDispatcher() &&
+        !target.IsInvokeFieldDispatcher()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
 void ICData::GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first,
                                    GrowableArray<intptr_t>* second) const {
   ASSERT(NumArgsTested() == 2);
@@ -14195,7 +14211,7 @@
     const char* name = StubCode::NameOfStub(UncheckedEntryPoint());
     return zone->PrintToString("[stub: %s]", name);
   } else {
-    return zone->PrintToString("Code entry:%" Px, UncheckedEntryPoint());
+    return zone->PrintToString("Code entry: 0x%" Px, UncheckedEntryPoint());
   }
 }
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 3e1ca78..b502dfc 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2069,6 +2069,7 @@
   bool AllTargetsHaveSameOwner(intptr_t owner_cid) const;
   bool AllReceiversAreNumbers() const;
   bool HasOneTarget() const;
+  bool HasOnlyDispatcherTargets() const;
   bool HasReceiverClassId(intptr_t class_id) const;
 
   static RawICData* New(const Function& owner,
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 11a7b3b..985617c 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -78,9 +78,54 @@
 
 class DartPrecompilationPipeline : public DartCompilationPipeline {
  public:
-  DartPrecompilationPipeline() : result_type_(CompileType::None()) { }
+  explicit DartPrecompilationPipeline(Zone* zone,
+                                      FieldTypeMap* field_map = NULL)
+      : zone_(zone),
+        result_type_(CompileType::None()),
+        field_map_(field_map) { }
 
   virtual void FinalizeCompilation(FlowGraph* flow_graph) {
+    if ((field_map_ != NULL )&&
+        flow_graph->function().IsGenerativeConstructor()) {
+      for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
+           !block_it.Done();
+           block_it.Advance()) {
+        ForwardInstructionIterator it(block_it.Current());
+        for (; !it.Done(); it.Advance()) {
+          StoreInstanceFieldInstr* store = it.Current()->AsStoreInstanceField();
+          if (store != NULL) {
+            if (!store->field().IsNull() && store->field().is_final()) {
+              if (FLAG_trace_precompiler && FLAG_support_il_printer) {
+                THR_Print("Found store to %s <- %s\n",
+                          store->field().ToCString(),
+                          store->value()->Type()->ToCString());
+              }
+              FieldTypePair* entry = field_map_->Lookup(&store->field());
+              if (entry == NULL) {
+                field_map_->Insert(FieldTypePair(
+                    &Field::Handle(zone_, store->field().raw()),  // Re-wrap.
+                    store->value()->Type()->ToCid()));
+                if (FLAG_trace_precompiler && FLAG_support_il_printer) {
+                    THR_Print(" initial type = %s\n",
+                              store->value()->Type()->ToCString());
+                }
+                continue;
+              }
+              CompileType type = CompileType::FromCid(entry->cid_);
+              if (FLAG_trace_precompiler && FLAG_support_il_printer) {
+                  THR_Print(" old type = %s\n", type.ToCString());
+              }
+              type.Union(store->value()->Type());
+              if (FLAG_trace_precompiler && FLAG_support_il_printer) {
+                  THR_Print(" new type = %s\n", type.ToCString());
+              }
+              entry->cid_ = type.ToCid();
+            }
+          }
+        }
+      }
+    }
+
     CompileType result_type = CompileType::None();
     for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
          !block_it.Done();
@@ -99,7 +144,9 @@
   CompileType result_type() { return result_type_; }
 
  private:
+  Zone* zone_;
   CompileType result_type_;
+  FieldTypeMap* field_map_;
 };
 
 
@@ -154,6 +201,92 @@
 }
 
 
+bool TypeRangeCache::InstanceOfHasClassRange(const AbstractType& type,
+                                             intptr_t* lower_limit,
+                                             intptr_t* upper_limit) {
+  ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
+
+  if (!type.IsInstantiated()) return false;
+  if (type.IsFunctionType()) return false;
+
+  Zone* zone = thread_->zone();
+  const TypeArguments& type_arguments =
+      TypeArguments::Handle(zone, type.arguments());
+  if (!type_arguments.IsNull() &&
+      !type_arguments.IsRaw(0, type_arguments.Length())) return false;
+
+
+  intptr_t type_cid = type.type_class_id();
+  if (lower_limits_[type_cid] == kNotContiguous) return false;
+  if (lower_limits_[type_cid] != kNotComputed) {
+    *lower_limit = lower_limits_[type_cid];
+    *upper_limit = upper_limits_[type_cid];
+    return true;
+  }
+
+
+  *lower_limit = -1;
+  *upper_limit = -1;
+  intptr_t last_matching_cid = -1;
+
+  ClassTable* table = thread_->isolate()->class_table();
+  Class& cls = Class::Handle(zone);
+  AbstractType& cls_type = AbstractType::Handle(zone);
+  for (intptr_t cid = kInstanceCid; cid < table->NumCids(); cid++) {
+    if (!table->HasValidClassAt(cid)) continue;
+    if (cid == kVoidCid) continue;
+    if (cid == kDynamicCid) continue;
+    cls = table->At(cid);
+    if (cls.is_abstract()) continue;
+    if (cls.is_patch()) continue;
+    if (cls.IsTopLevel()) continue;
+
+    cls_type = cls.RareType();
+    if (cls_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
+      last_matching_cid = cid;
+      if (*lower_limit == -1) {
+        // Found beginning of range.
+        *lower_limit = cid;
+      } else if (*upper_limit == -1) {
+        // Expanding range.
+      } else {
+        // Found a second range.
+        lower_limits_[type_cid] = kNotContiguous;
+        return false;
+      }
+    } else {
+      if (*lower_limit == -1) {
+        // Still before range.
+      } else if (*upper_limit == -1) {
+        // Found end of range.
+        *upper_limit = last_matching_cid;
+      } else {
+        // After range.
+      }
+    }
+  }
+  if (*lower_limit == -1) {
+    // Not implemented by any concrete class.
+    *lower_limit = kIllegalCid;
+    *upper_limit = kIllegalCid;
+  }
+
+  if (*upper_limit == -1) {
+    ASSERT(last_matching_cid != -1);
+    *upper_limit = last_matching_cid;
+  }
+
+  if (FLAG_trace_precompiler) {
+    THR_Print("Type check for %s is cid range [%" Pd ", %" Pd "]\n",
+              type.ToCString(), *lower_limit, *upper_limit);
+  }
+
+  lower_limits_[type_cid] = *lower_limit;
+  upper_limits_[type_cid] = *upper_limit;
+  return true;
+}
+
+
 Precompiler::Precompiler(Thread* thread, bool reset_fields) :
     thread_(thread),
     zone_(NULL),
@@ -180,6 +313,7 @@
     typeargs_to_retain_(),
     types_to_retain_(),
     consts_to_retain_(),
+    field_type_map_(),
     error_(Error::Handle()) {
 }
 
@@ -199,10 +333,15 @@
       FinalizeAllClasses();
 
       SortClasses();
+      TypeRangeCache trc(T, I->class_table()->NumCids());
 
       // Precompile static initializers to compute result type information.
       PrecompileStaticInitializers();
 
+      // Precompile constructors to compute type information for final fields.
+      ClearAllCode();
+      PrecompileConstructors();
+
       for (intptr_t round = 0; round < FLAG_precompiler_rounds; round++) {
         if (FLAG_trace_precompiler) {
           THR_Print("Precompiler round %" Pd "\n", round);
@@ -339,6 +478,52 @@
 }
 
 
+void Precompiler::PrecompileConstructors() {
+  class ConstructorVisitor : public FunctionVisitor {
+   public:
+    explicit ConstructorVisitor(Zone* zone, FieldTypeMap* map)
+        : zone_(zone), field_type_map_(map) {
+      ASSERT(map != NULL);
+    }
+    void Visit(const Function& function) {
+      if (!function.IsGenerativeConstructor()) return;
+      if (function.HasCode()) {
+        // Const constructors may have been visited before. Recompile them here
+        // to collect type information for final fields for them as well.
+        function.ClearCode();
+      }
+      if (FLAG_trace_precompiler) {
+        THR_Print("Precompiling constructor %s\n", function.ToCString());
+      }
+      CompileFunction(Thread::Current(),
+                      zone_,
+                      function,
+                      field_type_map_);
+    }
+   private:
+    Zone* zone_;
+    FieldTypeMap* field_type_map_;
+  };
+
+  HANDLESCOPE(T);
+  ConstructorVisitor visitor(zone_, &field_type_map_);
+  VisitFunctions(&visitor);
+
+  FieldTypeMap::Iterator it(field_type_map_.GetIterator());
+  for (FieldTypePair* current = it.Next();
+       current != NULL;
+       current = it.Next()) {
+    const intptr_t cid = current->cid_;
+    current->field_->set_guarded_cid(cid);
+    current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid);
+    if (FLAG_trace_precompiler) {
+      THR_Print("Field %s <- Type %s\n", current->field_->ToCString(),
+          Class::Handle(T->isolate()->class_table()->At(cid)).ToCString());
+    }
+  }
+}
+
+
 void Precompiler::ClearAllCode() {
   class ClearCodeFunctionVisitor : public FunctionVisitor {
     void Visit(const Function& function) {
@@ -609,7 +794,7 @@
     ASSERT(!function.is_abstract());
     ASSERT(!function.IsRedirectingFactory());
 
-    error_ = CompileFunction(thread_, function);
+    error_ = CompileFunction(thread_, zone_, function);
     if (!error_.IsNull()) {
       Jump(error_);
     }
@@ -946,7 +1131,7 @@
   ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
 
   parsed_function->AllocateVariables();
-  DartPrecompilationPipeline pipeline;
+  DartPrecompilationPipeline pipeline(zone.GetZone());
   PrecompileParsedFunctionHelper helper(parsed_function,
                                         /* optimized = */ true);
   bool success = helper.Compile(&pipeline);
@@ -1046,7 +1231,7 @@
     parsed_function->AllocateVariables();
 
     // Non-optimized code generator.
-    DartPrecompilationPipeline pipeline;
+    DartPrecompilationPipeline pipeline(Thread::Current()->zone());
     PrecompileParsedFunctionHelper helper(parsed_function,
                                           /* optimized = */ false);
     helper.Compile(&pipeline);
@@ -2489,7 +2674,7 @@
     if (val == 0) {
       FlowGraph* flow_graph = NULL;
 
-      // Class hierarchy analysis is registered with the isolate in the
+      // Class hierarchy analysis is registered with the thread in the
       // constructor and unregisters itself upon destruction.
       CHA cha(thread());
 
@@ -3073,16 +3258,16 @@
 
 
 RawError* Precompiler::CompileFunction(Thread* thread,
-                                       const Function& function) {
+                                       Zone* zone,
+                                       const Function& function,
+                                       FieldTypeMap* field_type_map) {
   VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
   TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function);
 
-  CompilationPipeline* pipeline =
-      CompilationPipeline::New(thread->zone(), function);
-
   ASSERT(FLAG_precompiled_mode);
   const bool optimized = function.IsOptimizable();  // False for natives.
-  return PrecompileFunctionHelper(pipeline, function, optimized);
+  DartPrecompilationPipeline pipeline(zone, field_type_map);
+  return PrecompileFunctionHelper(&pipeline, function, optimized);
 }
 
 #endif  // DART_PRECOMPILER
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 38e16fe..774dbd5 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -22,6 +22,42 @@
 class SequenceNode;
 class String;
 
+
+class TypeRangeCache : public StackResource {
+ public:
+  TypeRangeCache(Thread* thread, intptr_t num_cids)
+      : StackResource(thread),
+        thread_(thread),
+        lower_limits_(thread->zone()->Alloc<intptr_t>(num_cids)),
+        upper_limits_(thread->zone()->Alloc<intptr_t>(num_cids)) {
+    for (intptr_t i = 0; i < num_cids; i++) {
+      lower_limits_[i] = kNotComputed;
+      upper_limits_[i] = kNotComputed;
+    }
+    // We don't re-enter the precompiler.
+    ASSERT(thread->type_range_cache() == NULL);
+    thread->set_type_range_cache(this);
+  }
+
+  ~TypeRangeCache() {
+    ASSERT(thread_->type_range_cache() == this);
+    thread_->set_type_range_cache(NULL);
+  }
+
+  bool InstanceOfHasClassRange(const AbstractType& type,
+                               intptr_t* lower_limit,
+                               intptr_t* upper_limit);
+
+ private:
+  static const intptr_t kNotComputed = -1;
+  static const intptr_t kNotContiguous = -2;
+
+  Thread* thread_;
+  intptr_t* lower_limits_;
+  intptr_t* upper_limits_;
+};
+
+
 class SymbolKeyValueTrait {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
@@ -259,13 +295,47 @@
 typedef DirectChainedHashMap<InstanceKeyValueTrait> InstanceSet;
 
 
+struct FieldTypePair {
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const Field* Key;
+  typedef intptr_t Value;
+  typedef FieldTypePair Pair;
+
+  static Key KeyOf(Pair kv) { return kv.field_; }
+
+  static Value ValueOf(Pair kv) { return kv.cid_; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->token_pos().value();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair.field_->raw() == key->raw();
+  }
+
+  FieldTypePair(const Field* f, intptr_t cid) : field_(f), cid_(cid) { }
+
+  FieldTypePair() : field_(NULL), cid_(-1) { }
+
+  void Print() const;
+
+  const Field* field_;
+  intptr_t cid_;
+};
+
+typedef DirectChainedHashMap<FieldTypePair> FieldTypeMap;
+
+
 class Precompiler : public ValueObject {
  public:
   static RawError* CompileAll(
       Dart_QualifiedFunctionName embedder_entry_points[],
       bool reset_fields);
 
-  static RawError* CompileFunction(Thread* thread, const Function& function);
+  static RawError* CompileFunction(Thread* thread,
+                                   Zone* zone,
+                                   const Function& function,
+                                   FieldTypeMap* field_type_map = NULL);
 
   static RawObject* EvaluateStaticInitializer(const Field& field);
   static RawObject* ExecuteOnce(SequenceNode* fragment);
@@ -276,7 +346,6 @@
  private:
   Precompiler(Thread* thread, bool reset_fields);
 
-
   void DoCompileAll(Dart_QualifiedFunctionName embedder_entry_points[]);
   void ClearAllCode();
   void AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]);
@@ -321,6 +390,7 @@
   void CollectDynamicFunctionNames();
 
   void PrecompileStaticInitializers();
+  void PrecompileConstructors();
 
   template<typename T>
   class Visitor : public ValueObject {
@@ -369,6 +439,7 @@
   TypeArgumentsSet typeargs_to_retain_;
   AbstractTypeSet types_to_retain_;
   InstanceSet consts_to_retain_;
+  FieldTypeMap field_type_map_;
   Error& error_;
 };
 
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 104d22c..d35f0e1 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2306,7 +2306,7 @@
   }
   DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
   intptr_t framePos = UIntParameter::Parse(js->LookupParam("frameIndex"));
-  if (framePos > stack->Length()) {
+  if (framePos >= stack->Length()) {
     PrintInvalidParamError(js, "frameIndex");
     return true;
   }
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index d6891e2..0062dac 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -733,10 +733,10 @@
   // This head also provides the gap to make the instructions snapshot
   // look like a HeapPage.
   intptr_t instructions_length = next_offset_;
-  WriteWordLiteral(instructions_length);
+  WriteWordLiteralText(instructions_length);
   intptr_t header_words = InstructionsSnapshot::kHeaderSize / sizeof(uword);
   for (intptr_t i = 1; i < header_words; i++) {
-    WriteWordLiteral(0);
+    WriteWordLiteralText(0);
   }
 
   Object& owner = Object::Handle(zone);
@@ -763,13 +763,13 @@
       marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags);
       marked_tags = RawObject::MarkBit::update(true, marked_tags);
 
-      WriteWordLiteral(marked_tags);
+      WriteWordLiteralText(marked_tags);
       beginning += sizeof(uword);
 
       for (uword* cursor = reinterpret_cast<uword*>(beginning);
            cursor < reinterpret_cast<uword*>(entry);
            cursor++) {
-        WriteWordLiteral(*cursor);
+        WriteWordLiteralText(*cursor);
       }
     }
 
@@ -808,7 +808,7 @@
       for (uword* cursor = reinterpret_cast<uword*>(entry);
            cursor < reinterpret_cast<uword*>(end);
            cursor++) {
-        WriteWordLiteral(*cursor);
+        WriteWordLiteralText(*cursor);
       }
     }
   }
@@ -824,7 +824,7 @@
   // Start snapshot at page boundary.
   assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
   assembly_stream_.Print("_kDataSnapshot:\n");
-  WriteWordLiteral(next_object_offset_);  // Data length.
+  WriteWordLiteralData(next_object_offset_);  // Data length.
   COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment);
   assembly_stream_.Print(".balign %" Pd ", 0\n",
                          OS::kMaxPreferredCodeAlignment);
@@ -841,12 +841,12 @@
     uword marked_tags = obj.raw()->ptr()->tags_;
     marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags);
     marked_tags = RawObject::MarkBit::update(true, marked_tags);
-    WriteWordLiteral(marked_tags);
+    WriteWordLiteralData(marked_tags);
     start += sizeof(uword);
     for (uword* cursor = reinterpret_cast<uword*>(start);
          cursor < reinterpret_cast<uword*>(end);
          cursor++) {
-      WriteWordLiteral(*cursor);
+      WriteWordLiteralData(*cursor);
     }
   }
 }
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index a2f8197..3f767b8 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -751,7 +751,8 @@
   int32_t GetObjectOffsetFor(RawObject* raw_object);
 
   virtual void Write() = 0;
-  virtual intptr_t binary_size() = 0;
+  virtual intptr_t text_size() = 0;
+  virtual intptr_t data_size() = 0;
 
  protected:
   struct InstructionsData {
@@ -798,27 +799,40 @@
                              intptr_t initial_size)
     : InstructionsWriter(),
       assembly_stream_(assembly_buffer, alloc, initial_size),
-      binary_size_(0) {
+      text_size_(0),
+      data_size_(0) {
   }
 
   virtual void Write();
-  virtual intptr_t binary_size() { return binary_size_; }
+  virtual intptr_t text_size() { return text_size_; }
+  virtual intptr_t data_size() { return data_size_; }
 
   intptr_t AssemblySize() const { return assembly_stream_.bytes_written(); }
 
  private:
-  void WriteWordLiteral(uword value) {
+  void WriteWordLiteralText(uword value) {
     // Padding is helpful for comparing the .S with --disassemble.
 #if defined(ARCH_IS_64_BIT)
     assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
 #else
     assembly_stream_.Print(".long 0x%0.8" Px "\n", value);
 #endif
-    binary_size_ += sizeof(value);
+    text_size_ += sizeof(value);
+  }
+
+  void WriteWordLiteralData(uword value) {
+    // Padding is helpful for comparing the .S with --disassemble.
+#if defined(ARCH_IS_64_BIT)
+    assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
+#else
+    assembly_stream_.Print(".long 0x%0.8" Px "\n", value);
+#endif
+    data_size_ += sizeof(value);
   }
 
   WriteStream assembly_stream_;
-  intptr_t binary_size_;
+  intptr_t text_size_;
+  intptr_t data_size_;
 
   DISALLOW_COPY_AND_ASSIGN(AssemblyInstructionsWriter);
 };
@@ -836,9 +850,8 @@
   }
 
   virtual void Write();
-  virtual intptr_t binary_size() {
-    return InstructionsBlobSize() + RodataBlobSize();
-  }
+  virtual intptr_t text_size() { return InstructionsBlobSize(); }
+  virtual intptr_t data_size() { return RodataBlobSize(); }
 
   intptr_t InstructionsBlobSize() const {
     return instructions_blob_stream_.bytes_written();
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 6b40ac4..9aa510c 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -398,6 +398,8 @@
   V(DartLibrary, "dart.library.")                                              \
   V(DartLibraryMirrors, "dart.library.mirrors")                                \
   V(_name, "_name")                                                            \
+  V(_classRangeCheck, "_classRangeCheck")                                      \
+  V(_classRangeCheckNegative, "_classRangeCheckNegative")                      \
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 5115963..967bac0 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -90,6 +90,7 @@
       deferred_interrupts_(0),
       stack_overflow_count_(0),
       cha_(NULL),
+      type_range_cache_(NULL),
       deopt_id_(0),
       pending_functions_(GrowableObjectArray::null()),
       sticky_error_(Error::null()),
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 83bf04b..149a8e1 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -51,6 +51,7 @@
 class TimelineStream;
 class TypeArguments;
 class TypeParameter;
+class TypeRangeCache;
 class Zone;
 
 #define REUSABLE_HANDLE_LIST(V)                                                \
@@ -300,6 +301,11 @@
     cha_ = value;
   }
 
+  TypeRangeCache* type_range_cache() const { return type_range_cache_; }
+  void set_type_range_cache(TypeRangeCache* value) {
+    type_range_cache_ = value;
+  }
+
   int32_t no_callback_scope_depth() const {
     return no_callback_scope_depth_;
   }
@@ -692,6 +698,7 @@
 
   // Compiler state:
   CHA* cha_;
+  TypeRangeCache* type_range_cache_;
   intptr_t deopt_id_;  // Compilation specific counter.
   RawGrowableObjectArray* pending_functions_;
 
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 7e9ba2d..2627ac9 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -4,6 +4,8 @@
 
 #ifndef PRODUCT
 
+#include <errno.h>
+#include <fcntl.h>
 #include <cstdlib>
 
 #include "vm/atomic.h"
@@ -20,6 +22,7 @@
 
 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline");
 DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline");
+DEFINE_FLAG(bool, systrace_timeline, false, "Record the timeline to systrace");
 DEFINE_FLAG(bool, trace_timeline, false,
             "Trace timeline backend");
 DEFINE_FLAG(bool, trace_timeline_analysis, false,
@@ -35,7 +38,7 @@
             "GC, Isolate, and VM.");
 DEFINE_FLAG(charp, timeline_recorder, "ring",
             "Select the timeline recorder used. "
-            "Valid values: ring, endless, and startup.")
+            "Valid values: ring, endless, startup, and systrace.")
 
 // Implementation notes:
 //
@@ -86,9 +89,19 @@
       (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline;
 
   const bool use_startup_recorder = FLAG_startup_timeline;
+  const bool use_systrace_recorder = FLAG_systrace_timeline;
 
   const char* flag = FLAG_timeline_recorder;
 
+  if (use_systrace_recorder || (flag != NULL)) {
+    if (use_systrace_recorder || (strcmp("systrace", flag) == 0)) {
+      if (FLAG_trace_timeline) {
+        THR_Print("Using the Systrace timeline recorder.\n");
+      }
+      return new TimelineEventSystraceRecorder();
+    }
+  }
+
   if (use_endless_recorder || (flag != NULL)) {
     if (use_endless_recorder || (strcmp("endless", flag) == 0)) {
       if (FLAG_trace_timeline) {
@@ -497,6 +510,39 @@
 }
 
 
+intptr_t TimelineEvent::PrintSystrace(char* buffer, intptr_t buffer_size) {
+  ASSERT(buffer != NULL);
+  ASSERT(buffer_size > 0);
+  buffer[0] = '\0';
+  intptr_t length = 0;
+  int64_t pid = OS::ProcessId();
+  switch (event_type()) {
+    case kBegin: {
+      length = OS::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid, label());
+    }
+    break;
+    case kEnd: {
+      length = OS::SNPrint(buffer, buffer_size, "E");
+    }
+    break;
+    case kCounter: {
+      if (arguments_length_ > 0) {
+        // We only report the first counter value.
+        length = OS::SNPrint(buffer, buffer_size,
+                             "C|%" Pd64 "|%s|%s",
+                             pid,
+                             label(),
+                             arguments_[0].value);
+      }
+    }
+    default:
+      // Ignore event types that we cannot serialize to the Systrace format.
+    break;
+  }
+  return length;
+}
+
+
 void TimelineEvent::Complete() {
   TimelineEventRecorder* recorder = Timeline::recorder();
   if (recorder != NULL) {
@@ -1354,6 +1400,69 @@
 }
 
 
+TimelineEventSystraceRecorder::TimelineEventSystraceRecorder(intptr_t capacity)
+    : TimelineEventFixedBufferRecorder(capacity),
+      systrace_fd_(-1) {
+#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_LINUX)
+  const char* kSystracePath = "/sys/kernel/debug/tracing/trace_marker";
+  systrace_fd_ = open(kSystracePath, O_WRONLY);
+  if ((systrace_fd_ < 0) && FLAG_trace_timeline) {
+    OS::PrintErr("TimelineEventSystraceRecorder: Could not open `%s`\n",
+                 kSystracePath);
+  }
+#else
+  OS::PrintErr("Warning: The systrace timeline recorder is equivalent to the"
+               "ring recorder on this platform.");
+#endif
+}
+
+
+TimelineEventSystraceRecorder::~TimelineEventSystraceRecorder() {
+#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_LINUX)
+  if (systrace_fd_ >= 0) {
+    close(systrace_fd_);
+  }
+#endif
+}
+
+
+TimelineEventBlock* TimelineEventSystraceRecorder::GetNewBlockLocked() {
+  // TODO(johnmccutchan): This function should only hand out blocks
+  // which have been marked as finished.
+  if (block_cursor_ == num_blocks_) {
+    block_cursor_ = 0;
+  }
+  TimelineEventBlock* block = blocks_[block_cursor_++];
+  block->Reset();
+  block->Open();
+  return block;
+}
+
+
+void TimelineEventSystraceRecorder::CompleteEvent(TimelineEvent* event) {
+  if (event == NULL) {
+    return;
+  }
+#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_LINUX)
+  if (systrace_fd_ >= 0) {
+    // Serialize to the systrace format.
+    const intptr_t kBufferLength = 1024;
+    char buffer[kBufferLength];
+    const intptr_t event_length =
+        event->PrintSystrace(&buffer[0], kBufferLength);
+    if (event_length > 0) {
+      ssize_t __result;
+      // Repeatedly attempt the write while we are being interrupted.
+      do {
+        __result = write(systrace_fd_, buffer, event_length);
+      } while ((__result == -1L) && (errno == EINTR));
+    }
+  }
+#endif
+  ThreadBlockCompleteEvent(event);
+}
+
+
 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() {
   // TODO(johnmccutchan): This function should only hand out blocks
   // which have been marked as finished.
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index d91e909..851113f 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -342,6 +342,9 @@
     state_ = OwnsLabelBit::update(owns_label, state_);
   }
 
+  // Returns the number of bytes written into |buffer|.
+  intptr_t PrintSystrace(char* buffer, intptr_t buffer_size);
+
  private:
   void FreeArguments();
 
@@ -413,6 +416,7 @@
   friend class TimelineEventEndlessRecorder;
   friend class TimelineEventRingRecorder;
   friend class TimelineEventStartupRecorder;
+  friend class TimelineEventSystraceRecorder;
   friend class TimelineStream;
   friend class TimelineTestHelper;
   DISALLOW_COPY_AND_ASSIGN(TimelineEvent);
@@ -622,6 +626,7 @@
   friend class TimelineEventEndlessRecorder;
   friend class TimelineEventRingRecorder;
   friend class TimelineEventStartupRecorder;
+  friend class TimelineEventSystraceRecorder;
   friend class TimelineTestHelper;
   friend class JSONStream;
 
@@ -786,6 +791,28 @@
 };
 
 
+// A recorder that writes events to Android Systrace. Events are also stored in
+// a buffer of fixed capacity. When the buffer is full, new events overwrite
+// old events.
+class TimelineEventSystraceRecorder
+    : public TimelineEventFixedBufferRecorder {
+ public:
+  explicit TimelineEventSystraceRecorder(intptr_t capacity = kDefaultCapacity);
+
+  ~TimelineEventSystraceRecorder();
+
+  const char* name() const {
+    return "Systrace";
+  }
+
+ protected:
+  TimelineEventBlock* GetNewBlockLocked();
+  void CompleteEvent(TimelineEvent* event);
+
+  int systrace_fd_;
+};
+
+
 // A recorder that stores events in a buffer of fixed capacity. When the buffer
 // is full, new events are dropped.
 class TimelineEventStartupRecorder : public TimelineEventFixedBufferRecorder {
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index db764ee..e7f0e7a 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -175,6 +175,50 @@
 }
 
 
+TEST_CASE(TimelineEventPrintSystrace) {
+  const intptr_t kBufferLength = 1024;
+  char buffer[kBufferLength];
+
+  // Create a test stream.
+  TimelineStream stream;
+  stream.Init("testStream", true);
+
+  // Create a test event.
+  TimelineEvent event;
+  TimelineTestHelper::SetStream(&event, &stream);
+
+  // Test a Begin event.
+  event.Begin("apple", 1, 2);
+  event.PrintSystrace(&buffer[0], kBufferLength);
+  EXPECT_SUBSTRING("|apple", buffer);
+  EXPECT_SUBSTRING("B|", buffer);
+
+  // Test an End event.
+  event.End("apple", 2, 3);
+  event.PrintSystrace(&buffer[0], kBufferLength);
+  EXPECT_STREQ("E", buffer);
+
+  // Test a Counter event. We only report the first counter value (in this case
+  // "4").
+  event.Counter("CTR", 1);
+  // We have two counters.
+  event.SetNumArguments(2);
+  // Set the first counter value.
+  event.CopyArgument(0, "cats", "4");
+  // Set the second counter value.
+  event.CopyArgument(1, "dogs", "1");
+  event.PrintSystrace(&buffer[0], kBufferLength);
+  EXPECT_SUBSTRING("C|", buffer);
+  EXPECT_SUBSTRING("|CTR|4", buffer);
+
+  // Test a duration event. This event kind is not supported so we should
+  // serialize it to an empty string.
+  event.Duration("DUR", 0, 1, 2, 3);
+  event.PrintSystrace(&buffer[0], kBufferLength);
+  EXPECT_STREQ("", buffer);
+}
+
+
 TEST_CASE(TimelineEventArguments) {
   // Create a test stream.
   TimelineStream stream;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
index 4cbb163..b554437 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart
@@ -2930,6 +2930,7 @@
   }
   int fieldNumber = 0;
   for (String field in fields) {
+    if (r'$ti' == field) continue;  // Strip type info pseudofield.
     var metadata;
     if (fieldsMetadata != null) {
       metadata = fieldsMetadata[fieldNumber++];
diff --git a/sdk/lib/js_util/dart2js/js_util_dart2js.dart b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
index a587459..23a46e0 100644
--- a/sdk/lib/js_util/dart2js/js_util_dart2js.dart
+++ b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
@@ -12,7 +12,7 @@
 import 'dart:_foreign_helper' show JS;
 import 'dart:collection' show HashMap;
 
-/// WARNING: performance of this method is much worse than other uitil
+/// WARNING: performance of this method is much worse than other util
 /// methods in this library. Only use this method as a last resort.
 ///
 /// Recursively converts a JSON-like collection of Dart objects to a
@@ -20,7 +20,7 @@
 ///
 /// [object] must be a [Map] or [Iterable], the contents of which are also
 /// converted. Maps and Iterables are copied to a new JavaScript object.
-/// Primitives and other transferrable values are directly converted to their
+/// Primitives and other transferable values are directly converted to their
 /// JavaScript type, and all other objects are proxied.
 jsify(object) {
   if ((object is! Map) && (object is! Iterable)) {
diff --git a/sdk/lib/js_util/dartium/js_util_dartium.dart b/sdk/lib/js_util/dartium/js_util_dartium.dart
index 5f1226d..77386dc 100644
--- a/sdk/lib/js_util/dartium/js_util_dartium.dart
+++ b/sdk/lib/js_util/dartium/js_util_dartium.dart
@@ -11,7 +11,7 @@
 
 import 'dart:js';
 
-/// WARNING: performance of this method is much worse than other uitil
+/// WARNING: performance of this method is much worse than other util
 /// methods in this library. Only use this method as a last resort.
 ///
 /// Recursively converts a JSON-like collection of Dart objects to a
@@ -19,7 +19,7 @@
 ///
 /// [object] must be a [Map] or [Iterable], the contents of which are also
 /// converted. Maps and Iterables are copied to a new JavaScript object.
-/// Primitives and other transferrable values are directly converted to their
+/// Primitives and other transferable values are directly converted to their
 /// JavaScript type, and all other objects are proxied.
 jsify(object) {
   if ((object is! Map) && (object is! Iterable)) {
diff --git a/tests/compiler/dart2js/arithmetic_simplification_test.dart b/tests/compiler/dart2js/arithmetic_simplification_test.dart
index 039a844..a0a0efa 100644
--- a/tests/compiler/dart2js/arithmetic_simplification_test.dart
+++ b/tests/compiler/dart2js/arithmetic_simplification_test.dart
@@ -23,10 +23,12 @@
 }
 """;
 
+// TODO(johnniwinther): Find out why this doesn't work without the `as num`
+// cast.
 const String NUM_PLUS_ZERO = """
 int foo(x) => x;
 void main() {
-  var x = foo(0);
+  var x = foo(0) as num;
   return x + 0;
 }
 """;
@@ -81,8 +83,7 @@
   asyncTest(() => Future.wait([
     compileAndDoNotMatch(INT_PLUS_ZERO, 'main', plusZero),
     compileAndDoNotMatch(ZERO_PLUS_INT, 'main', zeroPlus),
-    // TODO(johnniwinther): Find out why this doesn't work without [useMock].
-    compileAndMatch(NUM_PLUS_ZERO, 'main', plusZero, useMock: true),
+    compileAndMatch(NUM_PLUS_ZERO, 'main', plusZero),
     compileAndMatch(ZERO_PLUS_NUM, 'main', zeroPlus),
     compileAndDoNotMatch(INT_TIMES_ONE, 'main', timesOne),
     compileAndDoNotMatch(ONE_TIMES_INT, 'main', oneTimes),
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index de673f8..6a142cd 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -25,7 +25,7 @@
         var parameter =
           printElement.functionSignature.requiredParameters.first;
         var type =
-            compiler.globalInference.getGuaranteedTypeOfElement(parameter);
+            compiler.globalInference.results.typeOf(parameter);
         checkType(compiler, type);
       }));
 
@@ -36,7 +36,7 @@
         var parameter =
           printElement.functionSignature.requiredParameters.first;
         var type =
-            compiler.globalInference.getGuaranteedTypeOfElement(parameter);
+            compiler.globalInference.results.typeOf(parameter);
         checkType(compiler, type);
       }));
 
@@ -47,7 +47,7 @@
         var parameter =
           printElement.functionSignature.requiredParameters.first;
         var type =
-            compiler.globalInference.getGuaranteedTypeOfElement(parameter);
+            compiler.globalInference.results.typeOf(parameter);
         checkType(compiler, type);
       }));
 }
@@ -91,13 +91,13 @@
         var inference = compiler.globalInference;
         Expect.identical(
             commonMasks.uint31Type,
-            inference.getGuaranteedTypeOfElement(firstParameter));
+            inference.results.typeOf(firstParameter));
         Expect.identical(
             commonMasks.nullType,
-            inference.getGuaranteedTypeOfElement(secondParameter));
+            inference.results.typeOf(secondParameter));
         Expect.identical(
             commonMasks.nullType,
-            inference.getGuaranteedTypeOfElement(thirdParameter));
+            inference.results.typeOf(thirdParameter));
       });
 }
 
diff --git a/tests/compiler/dart2js/jsinterop/abstract_test.dart b/tests/compiler/dart2js/jsinterop/abstract_test.dart
new file mode 100644
index 0000000..1579fa3
--- /dev/null
+++ b/tests/compiler/dart2js/jsinterop/abstract_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2016, 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 jsinterop.abstract_test;
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/common.dart';
+import '../memory_compiler.dart';
+
+void main() {
+  asyncTest(() async {
+    DiagnosticCollector collector = new DiagnosticCollector();
+    await runCompiler(
+        diagnosticHandler: collector,
+        memorySourceFiles: const {'main.dart': '''
+import 'package:js/js.dart';
+
+@JS()
+class A {
+  get foo;
+}
+
+main() => new A();
+'''});
+    Expect.equals(0, collector.errors.length,
+        'Unexpected error count.');
+    Expect.equals(1, collector.warnings.length,
+        'Unexpected warning count.');
+    Expect.equals(MessageKind.ABSTRACT_GETTER,
+        collector.warnings.first.messageKind,
+        'Unexpected warning.');
+  });
+}
\ No newline at end of file
diff --git a/tests/html/html.status b/tests/html/html.status
index 0c1830d..426bebd 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -34,9 +34,6 @@
 [ $compiler == dart2js && $checked ]
 js_function_getter_trust_types_test: Skip # --trust-type-annotations incompatible with --checked
 
-[ $compiler == dart2js && $checked && $browser && $runtime != drt]
-js_typed_interop_test/method: Fail # Issue 24822
-
 [ $compiler == dart2js && $csp && $browser ]
 custom/js_custom_test: Fail # Issue 14643
 custom/element_upgrade_test: Fail # Issue 17298
@@ -373,6 +370,8 @@
 js_typed_interop_test: SkipByDesign
 js_typed_interop_default_arg_test: SkipByDesign
 js_typed_interop_type_test: SkipByDesign
+js_typed_interop_type1_test: SkipByDesign
+js_typed_interop_type3_test: SkipByDesign
 js_typed_interop_window_property_test: SkipByDesign
 js_function_getter_test: SkipByDesign
 js_function_getter_trust_types_test: SkipByDesign
diff --git a/tests/html/js_typed_interop_type1_test.dart b/tests/html/js_typed_interop_type1_test.dart
new file mode 100644
index 0000000..bbb6ec5
--- /dev/null
+++ b/tests/html/js_typed_interop_type1_test.dart
@@ -0,0 +1,59 @@
+import 'dart:html';
+import 'package:js/js.dart';
+import 'package:expect/expect.dart';
+
+@JS()
+class A {
+  external get foo;
+
+  external A(var foo);
+}
+
+class F {
+  final foo;
+
+  F(this.foo);
+}
+
+@NoInline()
+testA(A o) {
+  return o.foo;
+}
+
+@NoInline()
+testF(F o) {
+  return o.foo;
+}
+
+
+_injectJs() {
+  document.body.append(new ScriptElement()
+    ..type = 'text/javascript'
+    ..innerHtml = r"""
+function A(foo) {
+  this.foo = foo;
+}
+""");
+}
+
+void expectValueOrTypeError(f(), value) {
+  try {
+    var i = 0;
+    String s = i; // Test for checked mode.
+    Expect.equals(f(), value);
+  } on TypeError catch (error) {
+    Expect.throws(f, (ex) => ex is TypeError);
+  }
+}
+
+main() {
+  _injectJs();
+
+  var a = new A(1);
+  var f = new F(6);
+
+  Expect.equals(testA(a), 1);
+  Expect.equals(testF(f), 6); /// 01: ok
+}
+
+
diff --git a/tests/html/js_typed_interop_type2_test.dart b/tests/html/js_typed_interop_type2_test.dart
new file mode 100644
index 0000000..6b3dbed
--- /dev/null
+++ b/tests/html/js_typed_interop_type2_test.dart
@@ -0,0 +1,53 @@
+import 'dart:html';
+import 'package:js/js.dart';
+import 'package:expect/expect.dart';
+
+@JS()
+@anonymous
+class C {
+  final foo;
+
+  external factory C({foo});
+}
+
+@JS()
+@anonymous
+class D {
+  final foo;
+
+  external factory D({foo});
+}
+
+class F {
+  final foo;
+
+  F(this.foo);
+}
+
+@NoInline()
+testC(C o) {
+  return o.foo;
+}
+
+@NoInline()
+testF(F o) {
+  return o.foo;
+}
+
+void expectValueOrTypeError(f(), value) {
+  try {
+    var i = 0;
+    String s = i; // Test for checked mode.
+  } on TypeError catch (error) {
+    Expect.throws(f, (ex) => ex is TypeError);
+  }
+}
+
+main() {
+  var d = new D(foo: 4);
+  var f = new F(6);
+  Expect.equals(testC(d), 4);
+  Expect.equals(testF(f), 6); /// 01: ok
+}
+
+
diff --git a/tests/html/js_typed_interop_type3_test.dart b/tests/html/js_typed_interop_type3_test.dart
new file mode 100644
index 0000000..f32d9f3
--- /dev/null
+++ b/tests/html/js_typed_interop_type3_test.dart
@@ -0,0 +1,88 @@
+import 'dart:html';
+import 'package:js/js.dart';
+import 'package:expect/expect.dart';
+
+@JS()
+class A {
+  external get foo;
+
+  external A(var foo);
+}
+
+@JS()
+@anonymous
+class C {
+  final foo;
+
+  external factory C({foo});
+}
+
+@JS()
+@anonymous
+class D {
+  final foo;
+
+  external factory D({foo});
+}
+
+class F {
+  final foo;
+
+  F(this.foo);
+}
+
+@NoInline()
+testA(A o) {
+  return o.foo;
+}
+
+@NoInline()
+testC(C o) {
+  return o.foo;
+}
+
+
+@NoInline()
+testD(D o) {
+  return o.foo;
+}
+
+@NoInline()
+testF(F o) {
+  return o.foo;
+}
+
+
+_injectJs() {
+  document.body.append(new ScriptElement()
+    ..type = 'text/javascript'
+    ..innerHtml = r"""
+function A(foo) {
+  this.foo = foo;
+}
+""");
+}
+
+void expectValueOrTypeError(f(), value) {
+  try {
+    var i = 0;
+    String s = i; // Test for checked mode.
+    Expect.equals(f(), value);
+  } on TypeError catch (error) {
+    Expect.throws(f, (ex) => ex is TypeError);
+  }
+}
+
+main() {
+  _injectJs();
+
+  var a = new A(1);
+  var d = new D(foo: 4);
+
+  Expect.equals(testA(a), 1); /// 01: ok
+  Expect.equals(testA(a), 1); /// 02: ok
+  Expect.equals(testA(d), 4);
+  Expect.equals(testD(d), 4); /// 02: continued
+}
+
+
diff --git a/tools/VERSION b/tools/VERSION
index b75955c..5b3f2a8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 20
 PATCH 0
-PRERELEASE 3
+PRERELEASE 4
 PRERELEASE_PATCH 0
diff --git a/tools/dartium/archive.py b/tools/dartium/archive.py
index 973731d..b499f02 100755
--- a/tools/dartium/archive.py
+++ b/tools/dartium/archive.py
@@ -132,7 +132,7 @@
 
 
 def Archive(srcpath, mode, dartium_target, contentshell_target,
-            chromedriver_target, is_win_ninja=False):
+            chromedriver_target):
   # We currently build using ninja on mac debug.
   if HOST_OS == 'mac':
     releaseDir = os.path.join(srcpath, 'out', mode)
@@ -142,10 +142,7 @@
     releaseDir = os.path.join(srcpath, 'out', mode)
     extra_files = []
   elif HOST_OS == 'win':
-    if is_win_ninja:
-      releaseDir = os.path.join(srcpath, 'out', mode)
-    else:
-      releaseDir = os.path.join(srcpath, 'out', mode)
+    releaseDir = os.path.join(srcpath, 'out', mode)
     # issue(16760) - we _need_ to fix our parsing of the FILES.cfg
     extra_files = [file for file in os.listdir(releaseDir) if file.endswith('manifest')]
   else:
diff --git a/tools/dartium/buildbot_annotated_steps.py b/tools/dartium/buildbot_annotated_steps.py
index c568b8e..0f69c1f 100755
--- a/tools/dartium/buildbot_annotated_steps.py
+++ b/tools/dartium/buildbot_annotated_steps.py
@@ -28,8 +28,7 @@
 # We limit testing on drt since it takes a long time to run.
 DRT_FILTER = 'html'
 
-def RunDartTests(mode, component, suite, arch, checked, test_filter=None,
-                 is_win_ninja=False):
+def RunDartTests(mode, component, suite, arch, checked, test_filter=None):
   """Runs tests using the Dart test.py or the layout test runner.
   """
   cmd = []
@@ -46,9 +45,6 @@
   cmd.append('--' + checked)
   cmd.append('--no-show-results')
 
-  if is_win_ninja:
-    cmd.append('--win-ninja-build')
-
   if test_filter:
     cmd.append('--test-filter=' + test_filter)
 
@@ -67,7 +63,7 @@
                                          'layout-test-results')
   shutil.rmtree(layout_test_results_dir, ignore_errors=True)
   status = RunDartTests(info.mode, component, suite, info.arch, checked,
-                        test_filter=test_filter, is_win_ninja=info.is_win_ninja)
+                        test_filter=test_filter)
     # Archive test failures
   if suite == 'layout' and status != 0:
     upload_steps.UploadDartTestsResults(layout_test_results_dir,
diff --git a/tools/dartium/test.py b/tools/dartium/test.py
index 0f16b41..ca48152 100755
--- a/tools/dartium/test.py
+++ b/tools/dartium/test.py
@@ -112,9 +112,6 @@
                     default=None,
                     action='store', type='string',
                     help='Test filter for core tests')
-  parser.add_option('--win-ninja-build', action='store_true',
-                    default=False, dest='is_win_ninja',
-                    help='We are on windows and use ninja for building.')
 
   (options, args) = parser.parse_args()
   mode = options.mode
@@ -158,8 +155,6 @@
     show_results = '--no-show-results'
 
   host_os = utils.guessOS()
-  if options.is_win_ninja:
-    host_os = 'win-ninja'
   build_root, drt_path, dartium_path, dart_path  = {
       'mac': (
         'out',
@@ -169,7 +164,6 @@
       ),
       'linux': ('out', 'content_shell', 'chrome', 'dart'),
       'win': ('out', 'content_shell.exe', 'chrome.exe', 'dart.exe'),
-      'win-ninja': ('out', 'content_shell.exe', 'chrome.exe', 'dart.exe'),
   }[host_os]
 
   build_dir = os.path.join(srcpath, build_root, mode)
diff --git a/tools/dartium/upload_steps.py b/tools/dartium/upload_steps.py
index d0a7cb0..c02517b 100755
--- a/tools/dartium/upload_steps.py
+++ b/tools/dartium/upload_steps.py
@@ -21,8 +21,10 @@
 
 BUILDER_NAME = 'BUILDBOT_BUILDERNAME'
 REVISION = 'BUILDBOT_REVISION'
-BUILDER_PATTERN = (r'^(dartium|multivm)-(mac|lucid64|lucid32|win)'
-   r'-(full|inc|debug|build)(-ninja)?(-(be|dev|stable|integration))?$')
+BUILDER_PATTERN = (r'^(dartium)-(mac|lucid64|lucid32|win)'
+    r'-(full|inc|debug)(-ninja)?(-(be|dev|stable|integration))?$')
+NEW_BUILDER_PATTERN = (
+    r'^dartium-(mac|linux|win)-(ia32|x64)(-inc)?-(be|dev|stable|integration)$')
 
 if platform.system() == 'Windows':
   GSUTIL = 'e:/b/build/scripts/slave/gsutil.bat'
@@ -49,29 +51,28 @@
     channel: the channel this build is happening on
     is_full: True if this is a full build.
     is_incremental: True if this is an incremental build.
-    is_build: True if this is a builder for the performance testers.
-    is_win_ninja: True if this is a ninja build on Windows.
 
   """
   def __init__(self, revision, version):
 
     self.revision = revision
     self.version = version
-    # Populate via builder environment variables.
     self.name = os.environ[BUILDER_NAME]
-    # Temporary hack, until we rename the FYI bots.
-    # We should eventually rename all to linux32 and linux64.
-    self.name = self.name.replace('-linux-', '-lucid64-')
-
-    self.is_incremental = '-inc' in self.name
-    self.is_win_ninja = 'win-inc-ninja' in self.name
-    pattern = re.match(BUILDER_PATTERN, self.name)
-    assert pattern
-    self.arch = 'x64' if pattern.group(2) == 'lucid64' else 'ia32'
-    self.mode = 'Debug' if pattern.group(3) == 'debug' else 'Release'
-    self.is_full = pattern.group(3) == 'full'
-    self.is_build = pattern.group(3) == 'build'
-    self.channel = pattern.group(6) if pattern.group(6) else 'be'
+    pattern = re.match(NEW_BUILDER_PATTERN, self.name)
+    if pattern:
+      self.arch = pattern.group(2)
+      self.mode = 'Release'
+      self.is_incremental = (pattern.group(3) == '-inc')
+      self.is_full = not self.is_incremental
+      self.channel = pattern.group(4)
+    else:
+      pattern = re.match(BUILDER_PATTERN, self.name)
+      assert pattern
+      self.arch = 'x64' if pattern.group(2) == 'lucid64' else 'ia32'
+      self.mode = 'Debug' if pattern.group(3) == 'debug' else 'Release'
+      self.is_incremental = '-inc' in self.name
+      self.is_full = pattern.group(3) == 'full'
+      self.channel = pattern.group(6) if pattern.group(6) else 'be'
 
 
 def ArchiveAndUpload(info, archive_latest=False):
@@ -79,7 +80,6 @@
   cwd = os.getcwd()
 
   dartium_bucket = info.name
-  dartium_bucket = dartium_bucket.replace('multivm', 'multivm-dartium')
   drt_bucket = dartium_bucket.replace('dartium', 'drt')
   chromedriver_bucket = dartium_bucket.replace('dartium', 'chromedriver')
   dartium_archive = dartium_bucket + '-' + info.version
@@ -90,8 +90,7 @@
       info.mode,
       dartium_archive,
       drt_archive,
-      chromedriver_archive,
-      is_win_ninja=info.is_win_ninja)
+      chromedriver_archive)
 
   status = 0
   # Upload bleeding-edge builds to old dartium-archive bucket
@@ -108,7 +107,7 @@
 
   # Upload to new dart-archive bucket using GCSNamer, but not incremental
   # or perf builder builds.
-  if not info.is_incremental and not info.is_build:
+  if not info.is_incremental:
     Upload('dartium', os.path.abspath(dartium_zip),
            info, archive_latest=archive_latest)
     Upload('drt', os.path.abspath(drt_zip),
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 8d6063a..d907204 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -46,7 +46,7 @@
   "mime_rev": "@75890811d4af5af080351ba8a2853ad4c8df98dd",
   "metatest_rev": "@e5aa8e4e19fc4188ac2f6d38368a47d8f07c3df1",
   "oauth2_rev": "@1bff41f4d54505c36f2d1a001b83b8b745c452f5",
-  "observatory_pub_packages_rev": "@e5e1e543bea10d4bed95b22ad3e7aa2b20a23584",
+  "observatory_pub_packages_rev": "@26aad88f1c1915d39bbcbff3cad589e2402fdcf1",
   "package_config_rev": "@0.1.3",
   "path_rev": "@b657c0854d1cf41c014986fa9d2321f1173df805",
   "plugin_tag": "@0.1.0",
diff --git a/tools/observatory_tool.py b/tools/observatory_tool.py
index 4cb5dbf..3cd09c9 100755
--- a/tools/observatory_tool.py
+++ b/tools/observatory_tool.py
@@ -21,7 +21,16 @@
     '*.concat.js',
     '*.scriptUrls',
     '*.precompiled.js',
-    'main.*',
+    'bower.json',
+    'package.json',
+    'CustomElements.*',
+    'dart_support.*',
+    'interop_support.*',
+    'HTMLImports.*',
+    'MutationObserver.*',
+    'ShadowDOM.*',
+    'webcomponents.*',
+    'webcomponents-lite.js',
     'unittest*',
     '*_buildLogs*',
     '*.log',
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 132d0c6..f8570c0 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -1854,8 +1854,24 @@
           void timeoutHandler() {
             timedOut = true;
             if (process != null) {
-              if (!process.kill()) {
-                DebugLogger.error("Unable to kill ${process.pid}");
+              if (io.Platform.isLinux) {
+                // Try to print stack traces of the timed out process.
+                io.Process.run('eu-stack', ['-p ${process.pid}'])
+                .then((result) {
+                  io.stdout.write(result.stdout);
+                  io.stderr.write(result.stderr);
+                })
+                .catchError(
+                    (error) => print("Error when printing stack trace: $error"))
+                .whenComplete(() {
+                  if (!process.kill()) {
+                    DebugLogger.error("Unable to kill ${process.pid}");
+                  }
+                });
+              } else {
+                if (!process.kill()) {
+                  DebugLogger.error("Unable to kill ${process.pid}");
+                }
               }
             }
           }