Version 1.9.0-dev.7.0

svn merge -r 43494:43548 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@43552 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 34531c6..9bac7d9 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -589,7 +589,8 @@
   }
 
   /**
-   * Returns `true` if there is a subscription for the given [server] and [file].
+   * Returns `true` if there is a subscription for the given [service] and
+   * [file].
    */
   bool hasAnalysisSubscription(AnalysisService service, String file) {
     Set<String> files = analysisServices[service];
@@ -699,9 +700,7 @@
    */
   void scheduleOperation(ServerOperation operation) {
     addOperation(operation);
-    if (!performOperationPending) {
-      _schedulePerformOperation();
-    }
+    _schedulePerformOperation();
   }
 
   /**
@@ -929,6 +928,15 @@
     });
   }
 
+  void test_flushResolvedUnit(String file) {
+    if (AnalysisEngine.isDartFileName(file)) {
+      AnalysisContextImpl context = getAnalysisContext(file);
+      Source source = getSource(file);
+      DartEntry dartEntry = context.getReadableSourceEntryOrNull(source);
+      dartEntry.flushAstStructures();
+    }
+  }
+
   /**
    * Implementation for `analysis.updateContent`.
    */
@@ -967,6 +975,7 @@
         throw new AnalysisException('Illegal change type');
       }
       _overlayState.setContents(source, newContents);
+      // Update all contexts.
       for (InternalAnalysisContext context in folderMap.values) {
         if (context.handleContentsChanged(
             source,
@@ -974,6 +983,28 @@
             newContents,
             true)) {
           schedulePerformAnalysisOperation(context);
+        } else {
+          // When the client sends any change for a source, we should resend
+          // subscribed notifications, even if there were no changes in the
+          // source contents.
+          // TODO(scheglov) consider checking if there are subscriptions.
+          if (AnalysisEngine.isDartFileName(file)) {
+            CompilationUnit dartUnit =
+                context.ensureAnyResolvedDartUnit(source);
+            if (dartUnit != null) {
+              AnalysisErrorInfo errorInfo = context.getErrors(source);
+              scheduleNotificationOperations(
+                  this,
+                  file,
+                  errorInfo.lineInfo,
+                  context,
+                  null,
+                  dartUnit,
+                  errorInfo.errors);
+            } else {
+              schedulePerformAnalysisOperation(context);
+            }
+          }
         }
       }
     });
@@ -1008,7 +1039,9 @@
    * Schedules [performOperation] exection.
    */
   void _schedulePerformOperation() {
-    assert(!performOperationPending);
+    if (performOperationPending) {
+      return;
+    }
     /*
      * TODO (danrubel) Rip out this workaround once the underlying problem
      * is fixed. Currently, the VM and dart:io do not deliver content
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 07a4fdc..ec612a5 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -20,6 +20,68 @@
 import 'package:analyzer/src/generated/source.dart';
 
 
+/**
+ * Schedules sending notifications for the given [file] using the resolved
+ * [resolvedDartUnit].
+ */
+void scheduleNotificationOperations(AnalysisServer server, String file,
+    LineInfo lineInfo, AnalysisContext context, CompilationUnit parsedDartUnit,
+    CompilationUnit resolvedDartUnit, List<AnalysisError> errors) {
+  // Only send notifications if the current context is the preferred
+  // context for the file.  This avoids redundant notification messages
+  // being sent to the client (see dartbug.com/22210).
+  // TODO(paulberry): note that there is a small risk that this will cause
+  // notifications to be lost if the preferred context for a file changes
+  // while analysis is in progress (e.g. because the client sent an
+  // analysis.setAnalysisRoots message).
+  if (server.getAnalysisContext(file) != context) {
+    return;
+  }
+  // Dart
+  CompilationUnit dartUnit =
+      resolvedDartUnit != null ? resolvedDartUnit : parsedDartUnit;
+  if (resolvedDartUnit != null) {
+    if (server.hasAnalysisSubscription(
+        protocol.AnalysisService.HIGHLIGHTS,
+        file)) {
+      server.scheduleOperation(
+          new _DartHighlightsOperation(file, resolvedDartUnit));
+    }
+    if (server.hasAnalysisSubscription(
+        protocol.AnalysisService.NAVIGATION,
+        file)) {
+      server.scheduleOperation(
+          new _DartNavigationOperation(file, resolvedDartUnit));
+    }
+    if (server.hasAnalysisSubscription(
+        protocol.AnalysisService.OCCURRENCES,
+        file)) {
+      server.scheduleOperation(
+          new _DartOccurrencesOperation(file, resolvedDartUnit));
+    }
+    if (server.hasAnalysisSubscription(
+        protocol.AnalysisService.OVERRIDES,
+        file)) {
+      server.scheduleOperation(
+          new _DartOverridesOperation(file, resolvedDartUnit));
+    }
+  }
+  if (dartUnit != null) {
+    if (server.hasAnalysisSubscription(
+        protocol.AnalysisService.OUTLINE,
+        file)) {
+      server.scheduleOperation(
+          new _DartOutlineOperation(file, lineInfo, dartUnit));
+    }
+  }
+  // errors
+  if (server.shouldSendErrorsNotificationFor(file)) {
+    server.scheduleOperation(
+        new _NotificationErrorsOperation(file, lineInfo, errors));
+  }
+}
+
+
 void sendAnalysisNotificationErrors(AnalysisServer server, String file,
     LineInfo lineInfo, List<AnalysisError> errors) {
   try {
@@ -173,61 +235,17 @@
       ChangeNotice notice = notices[i];
       Source source = notice.source;
       String file = source.fullName;
-      // Only send notifications if the current context is the preferred
-      // context for the file.  This avoids redundant notification messages
-      // being sent to the client (see dartbug.com/22210).
-      // TODO(paulberry): note that there is a small risk that this will cause
-      // notifications to be lost if the preferred context for a file changes
-      // while analysis is in progress (e.g. because the client sent an
-      // analysis.setAnalysisRoots message).
-      if (server.getAnalysisContext(file) != context) {
-        continue;
-      }
       // Dart
       CompilationUnit parsedDartUnit = notice.parsedDartUnit;
       CompilationUnit resolvedDartUnit = notice.resolvedDartUnit;
-      CompilationUnit dartUnit =
-          resolvedDartUnit != null ? resolvedDartUnit : parsedDartUnit;
-      if (resolvedDartUnit != null) {
-        if (server.hasAnalysisSubscription(
-            protocol.AnalysisService.HIGHLIGHTS,
-            file)) {
-          server.addOperation(
-              new _DartHighlightsOperation(file, resolvedDartUnit));
-        }
-        if (server.hasAnalysisSubscription(
-            protocol.AnalysisService.NAVIGATION,
-            file)) {
-          server.addOperation(
-              new _DartNavigationOperation(file, resolvedDartUnit));
-        }
-        if (server.hasAnalysisSubscription(
-            protocol.AnalysisService.OCCURRENCES,
-            file)) {
-          server.addOperation(
-              new _DartOccurrencesOperation(file, resolvedDartUnit));
-        }
-        if (server.hasAnalysisSubscription(
-            protocol.AnalysisService.OVERRIDES,
-            file)) {
-          server.addOperation(
-              new _DartOverridesOperation(file, resolvedDartUnit));
-        }
-      }
-      if (dartUnit != null) {
-        if (server.hasAnalysisSubscription(
-            protocol.AnalysisService.OUTLINE,
-            file)) {
-          LineInfo lineInfo = notice.lineInfo;
-          server.addOperation(
-              new _DartOutlineOperation(file, lineInfo, dartUnit));
-        }
-      }
-      // errors
-      if (server.shouldSendErrorsNotificationFor(file)) {
-        server.addOperation(
-            new _NotificationErrorsOperation(file, notice.lineInfo, notice.errors));
-      }
+      scheduleNotificationOperations(
+          server,
+          file,
+          notice.lineInfo,
+          context,
+          parsedDartUnit,
+          resolvedDartUnit,
+          notice.errors);
       // done
       server.fileAnalyzed(notice);
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
index 53ef0ec..8121738 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
@@ -185,7 +185,7 @@
     completion.write(')');
     CompletionSuggestion suggestion = new CompletionSuggestion(
         CompletionSuggestionKind.ARGUMENT_LIST,
-        COMPLETION_RELEVANCE_HIGH,
+        DART_RELEVANCE_HIGH,
         completion.toString(),
         completion.length,
         0,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
index 5435730..0e72827 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
@@ -178,7 +178,7 @@
       if (elem is ClassElement) {
         importedClassMap[name] = elem;
       }
-      _addSuggestion(elem, COMPLETION_RELEVANCE_DEFAULT);
+      _addSuggestion(elem, DART_RELEVANCE_DEFAULT);
     });
   }
 
@@ -202,7 +202,7 @@
                 if (elem is ClassElement) {
                   importedClassMap[name] = elem;
                 }
-                _addSuggestion(elem, COMPLETION_RELEVANCE_DEFAULT);
+                _addSuggestion(elem, DART_RELEVANCE_DEFAULT);
               });
             } else {
               // Exclude elements from prefixed imports
@@ -230,7 +230,7 @@
     if (completion != null && completion.length > 0) {
       suggestion = new CompletionSuggestion(
           CompletionSuggestionKind.INVOCATION,
-          COMPLETION_RELEVANCE_DEFAULT,
+          DART_RELEVANCE_DEFAULT,
           completion,
           completion.length,
           0,
@@ -258,7 +258,7 @@
             element.isPublic &&
             !excludedLibs.contains(element.library) &&
             !_importedCompletions.contains(element.displayName)) {
-          _addSuggestion(element, COMPLETION_RELEVANCE_LOW);
+          _addSuggestion(element, DART_RELEVANCE_LOW);
         }
       }
     });
@@ -334,7 +334,7 @@
 
   @override
   void visitClassElement(ClassElement element) {
-    cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
   }
 
   @override
@@ -349,16 +349,16 @@
 
   @override
   void visitFunctionElement(FunctionElement element) {
-    cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
   }
 
   @override
   void visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
-    cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
   }
 
   @override
   void visitTopLevelVariableElement(TopLevelVariableElement element) {
-    cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 44eacd6..54bb27d 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -23,12 +23,21 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 
-// TODO (danrubel) these are temporary constants as we transition completion
-// relevance from CompletionRelevance.LOW/DEFAULT/HIGH to int.
-// These should be removed in a subsequent CL
-const int COMPLETION_RELEVANCE_LOW = 500;
-const int COMPLETION_RELEVANCE_DEFAULT = 1000;
-const int COMPLETION_RELEVANCE_HIGH = 2000;
+// Relevance highest to lowest
+const int DART_RELEVANCE_HIGH = 2000;
+const int DART_RELEVANCE_LOCAL_VARIABLE = 1059;
+const int DART_RELEVANCE_PARAMETER = 1059;
+const int DART_RELEVANCE_INHERITED_FIELD = 1058;
+const int DART_RELEVANCE_LOCAL_FIELD = 1058;
+const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
+const int DART_RELEVANCE_INHERITED_METHOD = 1057;
+const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057;
+const int DART_RELEVANCE_LOCAL_METHOD = 1057;
+const int DART_RELEVANCE_LOCAL_FUNCTION = 1056;
+const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056;
+const int DART_RELEVANCE_KEYWORD = 1055;
+const int DART_RELEVANCE_DEFAULT = 1000;
+const int DART_RELEVANCE_LOW = 500;
 
 /**
  * The base class for computing code completion suggestions.
diff --git a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart b/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
index edbdd8e..7291fc6 100644
--- a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
@@ -111,7 +111,8 @@
   /**
    * Add imported element suggestions.
    */
-  void _addElementSuggestions(List<Element> elements) {
+  void _addElementSuggestions(List<Element> elements, {int relevance:
+      DART_RELEVANCE_DEFAULT}) {
     elements.forEach((Element elem) {
       if (elem is! ClassElement) {
         if (typesOnly) {
@@ -126,7 +127,7 @@
           }
         }
       }
-      addSuggestion(elem);
+      addSuggestion(elem, relevance: relevance);
     });
   }
 
@@ -149,14 +150,26 @@
         String name = inheritedTypes.removeLast();
         ClassElement elem = cache.importedClassMap[name];
         if (visited.add(name) && elem != null) {
-          _addElementSuggestions(elem.fields);
-          _addElementSuggestions(elem.accessors);
-          _addElementSuggestions(elem.methods);
+          _addElementSuggestions(
+              elem.fields,
+              relevance: DART_RELEVANCE_INHERITED_FIELD);
+          _addElementSuggestions(
+              elem.accessors,
+              relevance: DART_RELEVANCE_INHERITED_ACCESSOR);
+          _addElementSuggestions(
+              elem.methods,
+              relevance: DART_RELEVANCE_INHERITED_METHOD);
           elem.allSupertypes.forEach((InterfaceType type) {
             if (visited.add(type.name) && type.element != null) {
-              _addElementSuggestions(type.element.fields);
-              _addElementSuggestions(type.element.accessors);
-              _addElementSuggestions(type.element.methods);
+              _addElementSuggestions(
+                  type.element.fields,
+                  relevance: DART_RELEVANCE_INHERITED_FIELD);
+              _addElementSuggestions(
+                  type.element.accessors,
+                  relevance: DART_RELEVANCE_INHERITED_ACCESSOR);
+              _addElementSuggestions(
+                  type.element.methods,
+                  relevance: DART_RELEVANCE_INHERITED_METHOD);
             }
           });
         }
@@ -185,7 +198,7 @@
             request.suggestions.add(suggestion);
           }
         } else {
-          if (suggestion.relevance != COMPLETION_RELEVANCE_LOW) {
+          if (suggestion.relevance != DART_RELEVANCE_LOW) {
             request.suggestions.add(suggestion);
           }
         }
diff --git a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
index 6d7dd95..9913a63 100644
--- a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
@@ -144,9 +144,15 @@
     if (node is PrefixedIdentifier) {
       SimpleIdentifier prefix = node.prefix;
       if (prefix != null) {
-        Element element = prefix.bestElement;
-        if (element != null) {
-          return element.accept(this);
+        if (prefix.propagatedType != null) {
+          InterfaceTypeSuggestionBuilder.suggestionsFor(
+              request,
+              prefix.propagatedType);
+        } else {
+          Element element = prefix.bestElement;
+          if (element != null) {
+            return element.accept(this);
+          }
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
index a222062..b9588be 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
@@ -116,18 +116,18 @@
     if (firstDirective is! LibraryDirective) {
       if (firstDirective != null) {
         if (request.offset <= firstDirective.offset) {
-          _addSuggestions([Keyword.LIBRARY], COMPLETION_RELEVANCE_HIGH);
+          _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
         }
       } else {
         if (request.offset <= startOfDeclarations) {
-          _addSuggestions([Keyword.LIBRARY], COMPLETION_RELEVANCE_HIGH);
+          _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
         }
       }
     }
     if (request.offset <= startOfDeclarations) {
       _addSuggestions(
           [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART],
-          COMPLETION_RELEVANCE_HIGH);
+          DART_RELEVANCE_HIGH);
     }
     if (request.offset >= endOfDirectives) {
       _addSuggestions(
@@ -138,7 +138,7 @@
               Keyword.FINAL,
               Keyword.TYPEDEF,
               Keyword.VAR],
-          COMPLETION_RELEVANCE_HIGH);
+          DART_RELEVANCE_HIGH);
     }
   }
 
@@ -190,17 +190,17 @@
     // Very simplistic suggestion because analyzer will warn if
     // the extends / with / implements keywords are out of order
     if (node.extendsClause == null) {
-      _addSuggestion(Keyword.EXTENDS, COMPLETION_RELEVANCE_HIGH);
+      _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH);
     } else if (node.withClause == null) {
-      _addSuggestion(Keyword.WITH, COMPLETION_RELEVANCE_HIGH);
+      _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH);
     }
     if (node.implementsClause == null) {
-      _addSuggestion(Keyword.IMPLEMENTS, COMPLETION_RELEVANCE_HIGH);
+      _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH);
     }
   }
 
   void _addSuggestion(Keyword keyword, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
+      DART_RELEVANCE_DEFAULT]) {
     String completion = keyword.syntax;
     request.suggestions.add(
         new CompletionSuggestion(
@@ -214,7 +214,7 @@
   }
 
   void _addSuggestions(List<Keyword> keywords, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
+      DART_RELEVANCE_KEYWORD]) {
     keywords.forEach((Keyword keyword) {
       _addSuggestion(keyword, relevance);
     });
diff --git a/pkg/analysis_server/lib/src/services/completion/local_computer.dart b/pkg/analysis_server/lib/src/services/completion/local_computer.dart
index 0460537..4a7584f 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_computer.dart
@@ -160,7 +160,7 @@
       if (completion != null && completion.length > 0 && completion != '_') {
         CompletionSuggestion suggestion = new CompletionSuggestion(
             CompletionSuggestionKind.IDENTIFIER,
-            COMPLETION_RELEVANCE_DEFAULT,
+            DART_RELEVANCE_DEFAULT,
             completion,
             completion.length,
             0,
@@ -207,8 +207,11 @@
   @override
   void declaredClass(ClassDeclaration declaration) {
     bool isDeprecated = _isDeprecated(declaration);
-    CompletionSuggestion suggestion =
-        _addSuggestion(declaration.name, NO_RETURN_TYPE, isDeprecated);
+    CompletionSuggestion suggestion = _addSuggestion(
+        declaration.name,
+        NO_RETURN_TYPE,
+        isDeprecated,
+        DART_RELEVANCE_DEFAULT);
     if (suggestion != null) {
       suggestion.element = _createElement(
           protocol.ElementKind.CLASS,
@@ -222,8 +225,11 @@
   @override
   void declaredClassTypeAlias(ClassTypeAlias declaration) {
     bool isDeprecated = _isDeprecated(declaration);
-    CompletionSuggestion suggestion =
-        _addSuggestion(declaration.name, NO_RETURN_TYPE, isDeprecated);
+    CompletionSuggestion suggestion = _addSuggestion(
+        declaration.name,
+        NO_RETURN_TYPE,
+        isDeprecated,
+        DART_RELEVANCE_DEFAULT);
     if (suggestion != null) {
       suggestion.element = _createElement(
           protocol.ElementKind.CLASS_TYPE_ALIAS,
@@ -241,8 +247,12 @@
     }
     bool isDeprecated = _isDeprecated(fieldDecl) || _isDeprecated(varDecl);
     TypeName type = fieldDecl.fields.type;
-    CompletionSuggestion suggestion =
-        _addSuggestion(varDecl.name, type, isDeprecated, classDecl: fieldDecl.parent);
+    CompletionSuggestion suggestion = _addSuggestion(
+        varDecl.name,
+        type,
+        isDeprecated,
+        DART_RELEVANCE_LOCAL_FIELD,
+        classDecl: fieldDecl.parent);
     if (suggestion != null) {
       suggestion.element = _createElement(
           protocol.ElementKind.FIELD,
@@ -260,22 +270,29 @@
     TypeName returnType = declaration.returnType;
     bool isDeprecated = _isDeprecated(declaration);
     protocol.ElementKind kind;
+    int defaultRelevance = DART_RELEVANCE_DEFAULT;
     if (declaration.isGetter) {
       kind = protocol.ElementKind.GETTER;
+      defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
     } else if (declaration.isSetter) {
       if (excludeVoidReturn) {
         return;
       }
       kind = protocol.ElementKind.SETTER;
       returnType = NO_RETURN_TYPE;
+      defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
     } else {
       if (excludeVoidReturn && _isVoid(returnType)) {
         return;
       }
       kind = protocol.ElementKind.FUNCTION;
+      defaultRelevance = DART_RELEVANCE_LOCAL_FUNCTION;
     }
-    CompletionSuggestion suggestion =
-        _addSuggestion(declaration.name, returnType, isDeprecated);
+    CompletionSuggestion suggestion = _addSuggestion(
+        declaration.name,
+        returnType,
+        isDeprecated,
+        defaultRelevance);
     if (suggestion != null) {
       FormalParameterList param = declaration.functionExpression.parameters;
       suggestion.element = _createElement(
@@ -296,8 +313,11 @@
   void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {
     bool isDeprecated = _isDeprecated(declaration);
     TypeName returnType = declaration.returnType;
-    CompletionSuggestion suggestion =
-        _addSuggestion(declaration.name, returnType, isDeprecated);
+    CompletionSuggestion suggestion = _addSuggestion(
+        declaration.name,
+        returnType,
+        isDeprecated,
+        DART_RELEVANCE_DEFAULT);
     if (suggestion != null) {
       // TODO (danrubel) determine parameters and return type
       suggestion.element = _createElement(
@@ -319,7 +339,8 @@
     if (typesOnly) {
       return;
     }
-    CompletionSuggestion suggestion = _addSuggestion(name, type, false);
+    CompletionSuggestion suggestion =
+        _addSuggestion(name, type, false, DART_RELEVANCE_LOCAL_VARIABLE);
     if (suggestion != null) {
       suggestion.element =
           _createElement(protocol.ElementKind.LOCAL_VARIABLE, name, returnType: type);
@@ -334,27 +355,32 @@
     protocol.ElementKind kind;
     String parameters;
     TypeName returnType = declaration.returnType;
+    int defaultRelevance = DART_RELEVANCE_DEFAULT;
     if (declaration.isGetter) {
       kind = protocol.ElementKind.GETTER;
       parameters = null;
+      defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
     } else if (declaration.isSetter) {
       if (excludeVoidReturn) {
         return;
       }
       kind = protocol.ElementKind.SETTER;
       returnType = NO_RETURN_TYPE;
+      defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
     } else {
       if (excludeVoidReturn && _isVoid(returnType)) {
         return;
       }
       kind = protocol.ElementKind.METHOD;
       parameters = declaration.parameters.toSource();
+      defaultRelevance = DART_RELEVANCE_LOCAL_METHOD;
     }
     bool isDeprecated = _isDeprecated(declaration);
     CompletionSuggestion suggestion = _addSuggestion(
         declaration.name,
         returnType,
         isDeprecated,
+        defaultRelevance,
         classDecl: declaration.parent);
     if (suggestion != null) {
       suggestion.element = _createElement(
@@ -375,7 +401,8 @@
     if (typesOnly) {
       return;
     }
-    CompletionSuggestion suggestion = _addSuggestion(name, type, false);
+    CompletionSuggestion suggestion =
+        _addSuggestion(name, type, false, DART_RELEVANCE_PARAMETER);
     if (suggestion != null) {
       suggestion.element =
           _createElement(protocol.ElementKind.PARAMETER, name, returnType: type);
@@ -389,8 +416,11 @@
       return;
     }
     bool isDeprecated = _isDeprecated(varList) || _isDeprecated(varDecl);
-    CompletionSuggestion suggestion =
-        _addSuggestion(varDecl.name, varList.type, isDeprecated);
+    CompletionSuggestion suggestion = _addSuggestion(
+        varDecl.name,
+        varList.type,
+        isDeprecated,
+        DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
     if (suggestion != null) {
       suggestion.element = _createElement(
           protocol.ElementKind.TOP_LEVEL_VARIABLE,
@@ -436,13 +466,13 @@
   }
 
   CompletionSuggestion _addSuggestion(SimpleIdentifier id, TypeName returnType,
-      bool isDeprecated, {ClassDeclaration classDecl}) {
+      bool isDeprecated, int defaultRelevance, {ClassDeclaration classDecl}) {
     if (id != null) {
       String completion = id.name;
       if (completion != null && completion.length > 0 && completion != '_') {
         CompletionSuggestion suggestion = new CompletionSuggestion(
             CompletionSuggestionKind.INVOCATION,
-            isDeprecated ? COMPLETION_RELEVANCE_LOW : COMPLETION_RELEVANCE_DEFAULT,
+            isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
             completion,
             completion.length,
             0,
diff --git a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
index e7860ab..7bfeaab 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
@@ -126,17 +126,6 @@
   }
 
   @override
-  bool visitExpressionStatement(ExpressionStatement node) {
-    Expression expression = node.expression;
-    if (expression is SimpleIdentifier) {
-      if (expression.end < offset) {
-        return finished;
-      }
-    }
-    return visitNode(node);
-  }
-
-  @override
   bool visitForEachStatement(ForEachStatement node) {
     SimpleIdentifier id;
     TypeName type;
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index ef2902b..3a6d6ef 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -6,6 +6,7 @@
 
 import 'package:analysis_server/src/services/completion/completion_target.dart';
 import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * An [AstVisitor] for determining whether top level suggestions or invocation
@@ -193,6 +194,12 @@
   }
 
   @override
+  void visitConditionalExpression(ConditionalExpression node) {
+    optype.includeReturnValueSuggestions = true;
+    optype.includeTypeNameSuggestions = true;
+  }
+
+  @override
   visitConstructorName(ConstructorName node) {
     // some PrefixedIdentifier nodes are transformed into
     // ConstructorName nodes during the resolution process.
@@ -216,6 +223,14 @@
   }
 
   @override
+  void visitDefaultFormalParameter(DefaultFormalParameter node) {
+    if (identical(entity, node.defaultValue)) {
+      optype.includeReturnValueSuggestions = true;
+      optype.includeTypeNameSuggestions = true;
+    }
+  }
+
+  @override
   void visitDoStatement(DoStatement node) {
     if (identical(entity, node.condition)) {
       optype.includeReturnValueSuggestions = true;
@@ -247,6 +262,15 @@
 
   @override
   void visitExpressionStatement(ExpressionStatement node) {
+    // Given f[], the parser drops the [] from the expression statement
+    // but the [] token is the CompletionTarget entity
+    if (entity is Token) {
+      Token token = entity;
+      if (token.lexeme == '[]' && offset == token.offset + 1) {
+        optype.includeReturnValueSuggestions = true;
+        optype.includeTypeNameSuggestions = true;
+      }
+    }
   }
 
   @override
@@ -258,6 +282,17 @@
 
   @override
   void visitForEachStatement(ForEachStatement node) {
+    if (identical(entity, node.identifier)) {
+      optype.includeTypeNameSuggestions = true;
+    }
+    if (identical(entity, node.loopVariable)) {
+      optype.includeTypeNameSuggestions = true;
+    }
+    if (identical(entity, node.inKeyword) && offset <= node.inKeyword.offset) {
+      if (node.identifier == null && node.loopVariable == null) {
+        optype.includeTypeNameSuggestions = true;
+      }
+    }
     if (identical(entity, node.iterable)) {
       optype.includeReturnValueSuggestions = true;
       optype.includeTypeNameSuggestions = true;
@@ -307,6 +342,12 @@
   }
 
   @override
+  void visitIndexExpression(IndexExpression node) {
+    optype.includeReturnValueSuggestions = true;
+    optype.includeTypeNameSuggestions = true;
+  }
+
+  @override
   void visitInstanceCreationExpression(InstanceCreationExpression node) {
     if (identical(entity, node.constructorName)) {
       optype.includeTypeNameSuggestions = true;
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index b90b026..ba6c396 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -23,7 +23,7 @@
  */
 CompletionSuggestion createSuggestion(Element element,
     {CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
-    int relevance: COMPLETION_RELEVANCE_DEFAULT}) {
+    int relevance: DART_RELEVANCE_DEFAULT}) {
 
   String nameForType(DartType type) {
     if (type == null) {
@@ -58,7 +58,7 @@
   bool isDeprecated = element.isDeprecated;
   CompletionSuggestion suggestion = new CompletionSuggestion(
       kind,
-      isDeprecated ? COMPLETION_RELEVANCE_LOW : relevance,
+      isDeprecated ? DART_RELEVANCE_LOW : relevance,
       completion,
       completion.length,
       0,
@@ -186,7 +186,7 @@
   /**
    * Add a suggestion based upon the given element.
    */
-  void addSuggestion(Element element) {
+  void addSuggestion(Element element, {int relevance: DART_RELEVANCE_DEFAULT}) {
     if (element.isPrivate) {
       LibraryElement elementLibrary = element.library;
       LibraryElement unitLibrary = request.unit.element.library;
@@ -205,7 +205,7 @@
         !_completions.add(completion)) {
       return;
     }
-    CompletionSuggestion suggestion = createSuggestion(element, kind: kind);
+    CompletionSuggestion suggestion = createSuggestion(element, kind: kind, relevance: relevance);
     if (suggestion != null) {
       request.suggestions.add(suggestion);
     }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index 48390a2..0648eb3 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -140,22 +140,7 @@
       }
       String eol = utils.endOfLine;
       // prepare location for declaration
-      AstNode target_;
-      {
-        List<AstNode> nodes = _findNodes(occurrences);
-        AstNode commonParent = getNearestCommonAncestor(nodes);
-        if (commonParent is Block) {
-          List<AstNode> firstParents = getParents(nodes[0]);
-          int commonIndex = firstParents.indexOf(commonParent);
-          target_ = firstParents[commonIndex + 1];
-        } else {
-          target_ = _getEnclosingExpressionBody(commonParent);
-          if (target_ == null) {
-            target_ = commonParent.getAncestor((node) => node is Statement);
-          }
-        }
-      }
-      AstNode target = target_;
+      AstNode target = _findDeclarationTarget(occurrences);
       // insert variable declaration
       if (target is Statement) {
         String prefix = utils.getNodePrefix(target);
@@ -314,6 +299,32 @@
   }
 
   /**
+   * Return the [AstNode] to defined the variable before.
+   * It should be accessible by all the given [occurrences].
+   */
+  AstNode _findDeclarationTarget(List<SourceRange> occurrences) {
+    List<AstNode> nodes = _findNodes(occurrences);
+    AstNode commonParent = getNearestCommonAncestor(nodes);
+    // Block
+    if (commonParent is Block) {
+      List<AstNode> firstParents = getParents(nodes[0]);
+      int commonIndex = firstParents.indexOf(commonParent);
+      return firstParents[commonIndex + 1];
+    }
+    // ExpressionFunctionBody
+    AstNode expressionBody = _getEnclosingExpressionBody(commonParent);
+    if (expressionBody != null) {
+      return expressionBody;
+    }
+    // single Statement
+    AstNode target = commonParent.getAncestor((node) => node is Statement);
+    while (target.parent is! Block) {
+      target = target.parent;
+    }
+    return target;
+  }
+
+  /**
    * Returns [AstNode]s at the offsets of the given [SourceRange]s.
    */
   List<AstNode> _findNodes(List<SourceRange> ranges) {
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 1fbcaa3..f4d5bca 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -87,4 +87,43 @@
       expect(filesErrors[barPath], isEmpty);
     });
   }
+
+  test_sendNoticesAfterNopChange() async {
+    createProject();
+    addTestFile('');
+    await server.onAnalysisComplete;
+    // add an overlay
+    server.updateContent('1', {
+      testFile: new AddContentOverlay('main() {} main() {}')
+    });
+    await server.onAnalysisComplete;
+    // clear errors and make a no-op change
+    filesErrors.clear();
+    server.updateContent('2', {
+      testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')])
+    });
+    await server.onAnalysisComplete;
+    // errors should have been resent
+    expect(filesErrors, isNotEmpty);
+  }
+
+  test_sendNoticesAfterNopChange_flushedUnit() async {
+    createProject();
+    addTestFile('');
+    await server.onAnalysisComplete;
+    // add an overlay
+    server.updateContent('1', {
+      testFile: new AddContentOverlay('main() {} main() {}')
+    });
+    await server.onAnalysisComplete;
+    // clear errors and make a no-op change
+    filesErrors.clear();
+    server.test_flushResolvedUnit(testFile);
+    server.updateContent('2', {
+      testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')])
+    });
+    await server.onAnalysisComplete;
+    // errors should have been resent
+    expect(filesErrors, isNotEmpty);
+  }
 }
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index a7d7f56..aef1641 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -294,7 +294,7 @@
     v.!1length;
     v.!2getKeys;
   }
-}''', <String>["1+length", "2-getKeys"], failingTests: '1');
+}''', <String>["1+length", "2-getKeys"]);
 
     // Type propagation.
     buildTests('testCommentSnippets052', '''
@@ -305,7 +305,7 @@
     v.!1toUpperCase;
     v.!2getKeys;
   }
-}''', <String>["1+toUpperCase", "2-getKeys"], failingTests: '1');
+}''', <String>["1+toUpperCase", "2-getKeys"]);
 
     // Type propagation.
     buildTests('testCommentSnippets053', '''
@@ -316,7 +316,7 @@
     v.!1toUpperCase;
     v.!2getKeys;
   }
-}''', <String>["1+toUpperCase", "2-getKeys"], failingTests: '1');
+}''', <String>["1+toUpperCase", "2-getKeys"]);
 
     buildTests('testCommentSnippets054', '''
 class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}}
@@ -326,7 +326,7 @@
     v.!2toUpperCase;
     v.!3getKeys;
   }
-}''', <String>["1+isEmpty", "2+toUpperCase", "3-getKeys"], failingTests: '12');
+}''', <String>["1+isEmpty", "2+toUpperCase", "3-getKeys"]);
 
     buildTests('testCommentSnippets055', '''
 class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}}
@@ -345,16 +345,16 @@
     return;
   }
   v.!1toUpperCase;
-}''', <String>["1+toUpperCase"], failingTests: '1');
+}''', <String>["1+toUpperCase"]);
 
     // Type propagation.
     buildTests('testCommentSnippets057', '''
 class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}}
 void f(var v) {
-  if ((v as String).length == 0) {
+  if ((v as String).!2length == 0) {
     v.!1toUpperCase;
   }
-}''', <String>["1+toUpperCase"], failingTests: '1');
+}''', <String>["1+toUpperCase", "2+length"]);
 
     buildTests('testCommentSnippets058', '''
 typedef vo!2id callback(int k);
@@ -388,7 +388,7 @@
   v.!1toUpperCase;
   assert(v is String);
   v.!2toUpperCase;
-}''', <String>["1-toUpperCase", "2+toUpperCase"], failingTests: '2');
+}''', <String>["1-toUpperCase", "2+toUpperCase"]);
 
     buildTests('testCommentSnippets064', '''
 class Spline {
@@ -756,8 +756,7 @@
 
     buildTests('testCommentSnippets090', '''
 class X { f() { var a = 'x'; a.!1 }}''',
-        <String>["1+length"],
-        failingTests: '1');
+        <String>["1+length"]);
   }
 
   void buildCompletionTests() {
@@ -2246,8 +2245,7 @@
     buildTests(
         'test035',
         '''class Y {final x='hi';mth() {x.!1length;}}''',
-        <String>["1+length"],
-        failingTests: '1');
+        <String>["1+length"]);
 
     // TODO(scheglov) decide what to do with Type for untyped field (not
     // supported by the new store)
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index ded3d0d..08fa7e6 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -262,8 +262,8 @@
   }
 
   void assertHasResult(CompletionSuggestionKind kind, String completion,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated
-      = false, bool isPotential = false]) {
+      [int relevance = DART_RELEVANCE_DEFAULT, bool isDeprecated = false,
+      bool isPotential = false]) {
     var cs;
     suggestions.forEach((s) {
       if (s.completion == completion) {
@@ -445,11 +445,11 @@
       assertHasResult(
           CompletionSuggestionKind.KEYWORD,
           'import',
-          COMPLETION_RELEVANCE_HIGH);
+          DART_RELEVANCE_HIGH);
       assertHasResult(
           CompletionSuggestionKind.KEYWORD,
           'class',
-          COMPLETION_RELEVANCE_HIGH);
+          DART_RELEVANCE_HIGH);
     });
   }
 
@@ -469,9 +469,18 @@
       expect(replacementOffset, equals(completionOffset));
       expect(replacementLength, equals(0));
       assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'a');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'x');
+      assertHasResult(
+          CompletionSuggestionKind.INVOCATION,
+          'a',
+          DART_RELEVANCE_LOCAL_FIELD);
+      assertHasResult(
+          CompletionSuggestionKind.INVOCATION,
+          'b',
+          DART_RELEVANCE_LOCAL_VARIABLE);
+      assertHasResult(
+          CompletionSuggestionKind.INVOCATION,
+          'x',
+          DART_RELEVANCE_LOCAL_METHOD);
     });
   }
 
@@ -486,7 +495,10 @@
       expect(replacementLength, equals(4));
       // Suggestions based upon imported elements are partially filtered
       //assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'test');
+      assertHasResult(
+          CompletionSuggestionKind.INVOCATION,
+          'test',
+          DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
       assertNoResult('HtmlElement');
     });
   }
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index fd63c42..a77ccf8 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -10,7 +10,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_execution.dart';
 import 'package:analysis_server/src/protocol.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -31,13 +31,14 @@
 
 main() {
   group('ExecutionDomainHandler', () {
+    MemoryResourceProvider provider = new MemoryResourceProvider();
     AnalysisServer server;
     ExecutionDomainHandler handler;
 
     setUp(() {
       server = new AnalysisServer(
           new MockServerChannel(),
-          PhysicalResourceProvider.INSTANCE,
+          provider,
           new MockPackageMapProvider(),
           null,
           new AnalysisServerOptions(),
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 9bf0f76..2b3cad1 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -8,7 +8,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/protocol.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:unittest/unittest.dart';
 
@@ -21,7 +21,7 @@
 
   setUp(() {
     var serverChannel = new MockServerChannel();
-    var resourceProvider = PhysicalResourceProvider.INSTANCE;
+    var resourceProvider = new MemoryResourceProvider();
     server = new AnalysisServer(
         serverChannel,
         resourceProvider,
diff --git a/pkg/analysis_server/test/services/completion/combinator_computer_test.dart b/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
index e07cae5..4db0ad3 100644
--- a/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
@@ -62,26 +62,26 @@
     return computeFull((bool result) {
       assertSuggestClass(
           'A',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestClass(
           'B',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestClass(
           'PB',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestTopLevelVar(
           'T1',
           null,
-          COMPLETION_RELEVANCE_DEFAULT,
+          DART_RELEVANCE_DEFAULT,
           CompletionSuggestionKind.IDENTIFIER);
       assertSuggestFunction(
           'F1',
           'PB',
           false,
-          COMPLETION_RELEVANCE_DEFAULT,
+          DART_RELEVANCE_DEFAULT,
           CompletionSuggestionKind.IDENTIFIER);
       assertNotSuggested('C');
       assertNotSuggested('D');
@@ -115,36 +115,36 @@
     return computeFull((bool result) {
       assertSuggestClass(
           'A',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestClass(
           'B',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestClass(
           'PB',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestTopLevelVar(
           'T1',
           null,
-          COMPLETION_RELEVANCE_DEFAULT,
+          DART_RELEVANCE_DEFAULT,
           CompletionSuggestionKind.IDENTIFIER);
       assertSuggestFunction(
           'F1',
           'PB',
           false,
-          COMPLETION_RELEVANCE_DEFAULT,
+          DART_RELEVANCE_DEFAULT,
           CompletionSuggestionKind.IDENTIFIER);
       assertSuggestClass(
           'Clz',
-          relevance: COMPLETION_RELEVANCE_DEFAULT,
+          relevance: DART_RELEVANCE_DEFAULT,
           kind: CompletionSuggestionKind.IDENTIFIER);
       assertSuggestFunctionTypeAlias(
           'F2',
           null,
           false,
-          COMPLETION_RELEVANCE_DEFAULT,
+          DART_RELEVANCE_DEFAULT,
           CompletionSuggestionKind.IDENTIFIER);
       assertNotSuggested('C');
       assertNotSuggested('D');
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index f4f03ef..341b397 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -68,7 +68,7 @@
     manager = new DartCompletionManager.create(context, searchEngine, source);
     suggestion1 = new CompletionSuggestion(
         CompletionSuggestionKind.INVOCATION,
-        COMPLETION_RELEVANCE_DEFAULT,
+        DART_RELEVANCE_DEFAULT,
         "suggestion1",
         1,
         1,
@@ -76,7 +76,7 @@
         false);
     suggestion2 = new CompletionSuggestion(
         CompletionSuggestionKind.IDENTIFIER,
-        COMPLETION_RELEVANCE_DEFAULT,
+        DART_RELEVANCE_DEFAULT,
         "suggestion2",
         2,
         2,
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index 783d1a0..2764b587 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -14,7 +14,6 @@
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/completion/imported_computer.dart';
 import 'package:analysis_server/src/services/completion/invocation_computer.dart';
-import 'package:analysis_server/src/services/completion/local_computer.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/local_memory_index.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
@@ -115,8 +114,8 @@
 
   CompletionSuggestion assertSuggest(String completion,
       {CompletionSuggestionKind csKind: CompletionSuggestionKind.INVOCATION,
-      int relevance: COMPLETION_RELEVANCE_DEFAULT, protocol.ElementKind elemKind:
-      null, bool isDeprecated: false, bool isPotential: false}) {
+      int relevance: DART_RELEVANCE_DEFAULT, protocol.ElementKind elemKind: null,
+      bool isDeprecated: false, bool isPotential: false}) {
     CompletionSuggestion cs =
         getSuggest(completion: completion, csKind: csKind, elemKind: elemKind);
     if (cs == null) {
@@ -126,7 +125,7 @@
     }
     expect(cs.kind, equals(csKind));
     if (isDeprecated) {
-      expect(cs.relevance, equals(COMPLETION_RELEVANCE_LOW));
+      expect(cs.relevance, equals(DART_RELEVANCE_LOW));
     } else {
       expect(cs.relevance, equals(relevance));
     }
@@ -149,7 +148,7 @@
         paramTypes,
         cs.parameterNames,
         cs.parameterTypes);
-    expect(cs.relevance, COMPLETION_RELEVANCE_HIGH);
+    expect(cs.relevance, DART_RELEVANCE_HIGH);
   }
 
   void assertSuggestArgumentList_params(List<String> expectedNames,
@@ -181,7 +180,7 @@
   }
 
   CompletionSuggestion assertSuggestClass(String name, {int relevance:
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
       CompletionSuggestionKind.INVOCATION, bool isDeprecated: false}) {
     CompletionSuggestion cs = assertSuggest(
         name,
@@ -199,7 +198,7 @@
   }
 
   CompletionSuggestion assertSuggestClassTypeAlias(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     CompletionSuggestion cs =
         assertSuggest(name, csKind: kind, relevance: relevance);
@@ -214,7 +213,7 @@
   }
 
   CompletionSuggestion assertSuggestField(String name, String type,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
+      {int relevance: DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
       CompletionSuggestionKind.INVOCATION, bool isDeprecated: false}) {
     CompletionSuggestion cs = assertSuggest(
         name,
@@ -236,7 +235,7 @@
   }
 
   CompletionSuggestion assertSuggestFunction(String name, String returnType,
-      [bool isDeprecated = false, int relevance = COMPLETION_RELEVANCE_DEFAULT,
+      [bool isDeprecated = false, int relevance = DART_RELEVANCE_DEFAULT,
       CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
     CompletionSuggestion cs = assertSuggest(
         name,
@@ -261,9 +260,8 @@
   }
 
   CompletionSuggestion assertSuggestFunctionTypeAlias(String name,
-      String returnType, bool isDeprecated, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
-      CompletionSuggestionKind.INVOCATION]) {
+      String returnType, bool isDeprecated, [int relevance = DART_RELEVANCE_DEFAULT,
+      CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
     CompletionSuggestion cs = assertSuggest(
         name,
         csKind: kind,
@@ -289,7 +287,7 @@
   }
 
   CompletionSuggestion assertSuggestGetter(String name, String returnType,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
+      {int relevance: DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
       CompletionSuggestionKind.INVOCATION, bool isDeprecated: false}) {
     CompletionSuggestion cs = assertSuggest(
         name,
@@ -311,7 +309,7 @@
   }
 
   CompletionSuggestion assertSuggestLabel(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.IDENTIFIER]) {
     CompletionSuggestion cs =
         assertSuggest(name, csKind: kind, relevance: relevance);
@@ -328,7 +326,7 @@
   }
 
   CompletionSuggestion assertSuggestLibraryPrefix(String prefix, [int relevance
-      = COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      = DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     // Library prefix should only be suggested by ImportedComputer
     if (computer is ImportedComputer) {
@@ -346,29 +344,8 @@
     }
   }
 
-  CompletionSuggestion assertSuggestLocalVariable(String name,
-      String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT,
-      CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
-    // Local variables should only be suggested by LocalComputer
-    if (computer is LocalComputer) {
-      CompletionSuggestion cs =
-          assertSuggest(name, csKind: kind, relevance: relevance);
-      expect(cs.returnType, returnType != null ? returnType : 'dynamic');
-      protocol.Element element = cs.element;
-      expect(element, isNotNull);
-      expect(element.kind, equals(protocol.ElementKind.LOCAL_VARIABLE));
-      expect(element.name, equals(name));
-      expect(element.parameters, isNull);
-      expect(element.returnType, returnType != null ? returnType : 'dynamic');
-      assertHasNoParameterInfo(cs);
-      return cs;
-    } else {
-      return assertNotSuggested(name);
-    }
-  }
-
   CompletionSuggestion assertSuggestMethod(String name, String declaringType,
-      String returnType, {int relevance: COMPLETION_RELEVANCE_DEFAULT,
+      String returnType, {int relevance: DART_RELEVANCE_DEFAULT,
       CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
       bool isDeprecated: false}) {
     CompletionSuggestion cs = assertSuggest(
@@ -392,7 +369,7 @@
   }
 
   CompletionSuggestion assertSuggestNamedConstructor(String name,
-      String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT,
+      String returnType, [int relevance = DART_RELEVANCE_DEFAULT,
       CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
     if (computer is InvocationComputer) {
       CompletionSuggestion cs =
@@ -414,29 +391,12 @@
   }
 
   CompletionSuggestion assertSuggestParameter(String name, String returnType,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
-      CompletionSuggestionKind.INVOCATION]) {
-    // Parameters should only be suggested by LocalComputer
-    if (computer is LocalComputer) {
-      CompletionSuggestion cs =
-          assertSuggest(name, csKind: kind, relevance: relevance);
-      expect(cs.returnType, returnType != null ? returnType : 'dynamic');
-      protocol.Element element = cs.element;
-      expect(element, isNotNull);
-      expect(element.kind, equals(protocol.ElementKind.PARAMETER));
-      expect(element.name, equals(name));
-      expect(element.parameters, isNull);
-      expect(
-          element.returnType,
-          equals(returnType != null ? returnType : 'dynamic'));
-      return cs;
-    } else {
-      return assertNotSuggested(name);
-    }
+      {int relevance: DART_RELEVANCE_PARAMETER}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestSetter(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     CompletionSuggestion cs = assertSuggest(
         name,
@@ -458,7 +418,7 @@
   }
 
   CompletionSuggestion assertSuggestTopLevelVar(String name, String returnType,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      [int relevance = DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     CompletionSuggestion cs =
         assertSuggest(name, csKind: kind, relevance: relevance);
@@ -474,7 +434,7 @@
   }
 
   void assertSuggestTopLevelVarGetterSetter(String name, String returnType,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+      [int relevance = DART_RELEVANCE_DEFAULT]) {
     if (computer is ImportedComputer) {
       assertSuggestGetter(name, returnType);
       assertSuggestSetter(name);
@@ -624,22 +584,8 @@
     // Subclasses override
   }
 
-  CompletionSuggestion assertLocalSuggestMethod(String name,
-      String declaringType, String returnType, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is LocalComputer) {
-      return assertSuggestMethod(
-          name,
-          declaringType,
-          returnType,
-          relevance: relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
-  }
-
   CompletionSuggestion assertSuggestImportedClass(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     if (computer is ImportedComputer) {
       return assertSuggestClass(name, relevance: relevance, kind: kind);
@@ -649,13 +595,13 @@
   }
 
   CompletionSuggestion assertSuggestImportedField(String name, String type,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+      {int relevance: DART_RELEVANCE_INHERITED_FIELD}) {
     return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestImportedFunction(String name,
       String returnType, [bool isDeprecated = false, int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     if (computer is ImportedComputer) {
       return assertSuggestFunction(
@@ -671,7 +617,7 @@
 
   CompletionSuggestion assertSuggestImportedFunctionTypeAlias(String name,
       String returnType, [bool isDeprecated = false, int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     if (computer is ImportedComputer) {
       return assertSuggestFunctionTypeAlias(
@@ -686,39 +632,23 @@
   }
 
   CompletionSuggestion assertSuggestImportedGetter(String name,
-      String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is ImportedComputer) {
-      return assertSuggestGetter(name, returnType, relevance: relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+      String returnType, {int relevance: DART_RELEVANCE_INHERITED_ACCESSOR}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestImportedMethod(String name,
-      String declaringType, String returnType, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is ImportedComputer) {
-      return assertSuggestMethod(
-          name,
-          declaringType,
-          returnType,
-          relevance: relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+      String declaringType, String returnType, {int relevance:
+      DART_RELEVANCE_INHERITED_METHOD}) {
+    return assertNotSuggested(name);
   }
 
-  CompletionSuggestion assertSuggestImportedSetter(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is ImportedComputer) {
-      return assertSuggestSetter(name, relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+  CompletionSuggestion assertSuggestImportedSetter(String name, {int relevance:
+      DART_RELEVANCE_INHERITED_ACCESSOR}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestImportedTopLevelVar(String name,
-      String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT,
+      String returnType, [int relevance = DART_RELEVANCE_DEFAULT,
       CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
     if (computer is ImportedComputer) {
       return assertSuggestTopLevelVar(name, returnType, relevance, kind);
@@ -728,7 +658,7 @@
   }
 
   CompletionSuggestion assertSuggestInvocationClass(String name, [int relevance
-      = COMPLETION_RELEVANCE_DEFAULT]) {
+      = DART_RELEVANCE_DEFAULT]) {
     if (computer is InvocationComputer) {
       return assertSuggestClass(name, relevance: relevance);
     } else {
@@ -737,13 +667,13 @@
   }
 
   CompletionSuggestion assertSuggestInvocationField(String name, String type,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
     return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestInvocationGetter(String name,
-      String returnType, {int relevance: COMPLETION_RELEVANCE_DEFAULT,
-      bool isDeprecated: false}) {
+      String returnType, {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated:
+      false}) {
     if (computer is InvocationComputer) {
       return assertSuggestGetter(
           name,
@@ -757,7 +687,7 @@
 
   CompletionSuggestion assertSuggestInvocationMethod(String name,
       String declaringType, String returnType, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
+      DART_RELEVANCE_DEFAULT]) {
     if (computer is InvocationComputer) {
       return assertSuggestMethod(
           name,
@@ -770,7 +700,7 @@
   }
 
   CompletionSuggestion assertSuggestInvocationSetter(String name, [int relevance
-      = COMPLETION_RELEVANCE_DEFAULT]) {
+      = DART_RELEVANCE_DEFAULT]) {
     if (computer is InvocationComputer) {
       return assertSuggestSetter(name);
     } else {
@@ -779,7 +709,7 @@
   }
 
   CompletionSuggestion assertSuggestInvocationTopLevelVar(String name,
-      String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+      String returnType, [int relevance = DART_RELEVANCE_DEFAULT]) {
     if (computer is InvocationComputer) {
       return assertSuggestTopLevelVar(name, returnType, relevance);
     } else {
@@ -788,79 +718,60 @@
   }
 
   CompletionSuggestion assertSuggestLocalClass(String name, {int relevance:
-      COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
     return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalClassTypeAlias(String name,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is LocalComputer) {
-      return assertSuggestClassTypeAlias(name, relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+      {int relevance: DART_RELEVANCE_DEFAULT}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalField(String name, String type,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_LOCAL_FIELD, bool deprecated: false}) {
     return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalFunction(String name,
-      String returnType, [bool isDeprecated = false, int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is LocalComputer) {
-      return assertSuggestFunction(name, returnType, isDeprecated, relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+      String returnType, {bool deprecated: false, int relevance:
+      DART_RELEVANCE_LOCAL_FUNCTION}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalFunctionTypeAlias(String name,
-      String returnType, [bool isDeprecated = false, int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is LocalComputer) {
-      return assertSuggestFunctionTypeAlias(
-          name,
-          returnType,
-          isDeprecated,
-          relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+      String returnType, {bool deprecated: false, int relevance:
+      DART_RELEVANCE_DEFAULT}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalGetter(String name, String returnType,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_LOCAL_ACCESSOR, bool deprecated: false}) {
     return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalMethod(String name,
       String declaringType, String returnType, {int relevance:
-      COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      DART_RELEVANCE_LOCAL_METHOD, bool deprecated: false}) {
     return assertNotSuggested(name);
   }
 
-  CompletionSuggestion assertSuggestLocalSetter(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is LocalComputer) {
-      return assertSuggestSetter(name, relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+  CompletionSuggestion assertSuggestLocalSetter(String name, {int relevance:
+      DART_RELEVANCE_LOCAL_ACCESSOR}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestLocalTopLevelVar(String name,
-      String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
-    if (computer is LocalComputer) {
-      return assertSuggestTopLevelVar(name, returnType, relevance);
-    } else {
-      return assertNotSuggested(name);
-    }
+      String returnType, {int relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE}) {
+    return assertNotSuggested(name);
+  }
+
+  CompletionSuggestion assertSuggestLocalVariable(String name,
+      String returnType, {int relevance: DART_RELEVANCE_LOCAL_VARIABLE}) {
+    return assertNotSuggested(name);
   }
 
   CompletionSuggestion assertSuggestNonLocalClass(String name, [int relevance =
-      COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+      DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
       CompletionSuggestionKind.INVOCATION]) {
     return assertSuggestImportedClass(name, relevance, kind);
   }
@@ -1230,8 +1141,8 @@
 
       assertSuggestLocalClass('X');
       assertSuggestLocalClass('Z');
-      assertLocalSuggestMethod('a', 'X', null);
-      assertLocalSuggestMethod('b', 'X', 'void');
+      assertSuggestLocalMethod('a', 'X', null);
+      assertSuggestLocalMethod('b', 'X', 'void');
       assertSuggestLocalFunction('localF', null);
       assertSuggestLocalVariable('f', null);
       // Don't suggest locals out of scope
@@ -1312,8 +1223,8 @@
 
       assertSuggestLocalClass('X');
       assertSuggestLocalClass('Z');
-      assertLocalSuggestMethod('a', 'X', null);
-      assertLocalSuggestMethod('b', 'X', 'void');
+      assertSuggestLocalMethod('a', 'X', null);
+      assertSuggestLocalMethod('b', 'X', 'void');
       assertSuggestLocalVariable('f', null);
       // Don't suggest locals out of scope
       assertNotSuggested('r');
@@ -1324,8 +1235,8 @@
       assertNotSuggested('_B');
       //assertSuggestImportedClass('C');
       // hidden element suggested as low relevance
-      assertSuggestImportedClass('D', COMPLETION_RELEVANCE_LOW);
-      assertSuggestImportedFunction('D1', null, true, COMPLETION_RELEVANCE_LOW);
+      assertSuggestImportedClass('D', DART_RELEVANCE_LOW);
+      assertSuggestImportedFunction('D1', null, true, DART_RELEVANCE_LOW);
       assertSuggestLocalFunction('D2', 'Z');
       //assertSuggestImportedClass('EE');
       // hidden element suggested as low relevance
@@ -1548,7 +1459,7 @@
       expect(request.replacementLength, 0);
       CompletionSuggestion suggestionA = assertSuggestLocalClass(
           'A',
-          relevance: COMPLETION_RELEVANCE_LOW,
+          relevance: DART_RELEVANCE_LOW,
           isDeprecated: true);
       if (suggestionA != null) {
         expect(suggestionA.element.isDeprecated, isTrue);
@@ -1621,35 +1532,120 @@
     });
   }
 
-  test_ConditionalExpression_empty() {
-    // SimpleIdentifier  PrefixIdentifier  IfStatement
+  test_ConditionalExpression_elseExpression() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
     addTestSource('''
-      class A {var b; X _c; foo() {A a; if (^) something}}''');
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} return a ? T1 : T^}}''');
     computeFast();
     return computeFull((bool result) {
-      expect(request.replacementOffset, completionOffset);
-      expect(request.replacementLength, 0);
-      assertSuggestLocalField('b', null);
-      assertSuggestLocalField('_c', 'X');
-      assertSuggestImportedClass('Object');
-      assertSuggestLocalClass('A');
-      assertNotSuggested('==');
+      // top level results are partially filtered based on first char
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
     });
   }
 
-  test_ConditionalExpression_invocation() {
-    // SimpleIdentifier  PrefixIdentifier  IfStatement
+  test_ConditionalExpression_elseExpression_empty() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
     addTestSource('''
-      main() {var a; if (a.^) something}''');
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} return a ? T1 : ^}}''');
     computeFast();
     return computeFull((bool result) {
-      expect(request.replacementOffset, completionOffset);
-      expect(request.replacementLength, 0);
-      assertSuggestInvocationMethod('toString', 'Object', 'String');
-      //TODO (danrubel) type for '_c' should be 'X' not null
-      assertNotSuggested('Object');
-      assertNotSuggested('A');
-      assertNotSuggested('==');
+      assertNotSuggested('x');
+      assertSuggestLocalVariable('f', null);
+      assertSuggestLocalMethod('foo', 'C', null);
+      assertSuggestLocalClass('C');
+      assertSuggestLocalFunction('F2', null);
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      assertSuggestImportedClass('A');
+      assertSuggestImportedFunction('F1', null);
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
+    });
+  }
+
+  test_ConditionalExpression_partial_thenExpression() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
+    addTestSource('''
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} return a ? T^}}''');
+    computeFast();
+    return computeFull((bool result) {
+      // top level results are partially filtered based on first char
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
+    });
+  }
+
+  test_ConditionalExpression_partial_thenExpression_empty() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
+    addTestSource('''
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} return a ? ^}}''');
+    computeFast();
+    return computeFull((bool result) {
+      assertNotSuggested('x');
+      assertSuggestLocalVariable('f', null);
+      assertSuggestLocalMethod('foo', 'C', null);
+      assertSuggestLocalClass('C');
+      assertSuggestLocalFunction('F2', null);
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      assertSuggestImportedClass('A');
+      assertSuggestImportedFunction('F1', null);
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
+    });
+  }
+
+  test_ConditionalExpression_thenExpression() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
+    addTestSource('''
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} return a ? T^ : c}}''');
+    computeFast();
+    return computeFull((bool result) {
+      // top level results are partially filtered based on first char
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
     });
   }
 
@@ -1763,6 +1759,25 @@
     });
   }
 
+  test_DefaultFormalParameter_named_expression() {
+    // DefaultFormalParameter FormalParameterList MethodDeclaration
+    addTestSource('''
+      foo() { }
+      void bar() { }
+      class A {a(blat: ^) { }}''');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertSuggestLocalFunction('foo', null);
+      assertSuggestLocalMethod('a', 'A', null);
+      assertSuggestLocalClass('A');
+      assertSuggestImportedClass('String');
+      assertSuggestImportedFunction('identical', 'bool');
+      assertNotSuggested('bar');
+    });
+  }
+
   test_ExpressionStatement_identifier() {
     // SimpleIdentifier  ExpressionStatement  Block
     addSource('/testA.dart', '''
@@ -1838,6 +1853,7 @@
     return computeFull((bool result) {
       expect(request.replacementOffset, completionOffset);
       expect(request.replacementLength, 0);
+      assertSuggestParameter('args', null);
       assertSuggestLocalVariable('foo', 'int');
       assertSuggestImportedClass('Object');
     });
@@ -1850,11 +1866,62 @@
     return computeFull((bool result) {
       expect(request.replacementOffset, completionOffset);
       expect(request.replacementLength, 0);
+      assertSuggestParameter('args', null);
       assertSuggestLocalVariable('foo', null);
       assertSuggestImportedClass('Object');
     });
   }
 
+  test_ForEachStatement_iterable() {
+    // SimpleIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (int foo in ^) {}}');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertSuggestParameter('args', null);
+      assertSuggestImportedClass('Object');
+    });
+  }
+
+  test_ForEachStatement_loopVariable() {
+    // SimpleIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (^ in args) {}}');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertNotSuggested('args');
+      assertSuggestImportedClass('String');
+    });
+  }
+
+  test_ForEachStatement_loopVariable_type() {
+    // SimpleIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (^ foo in args) {}}');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertNotSuggested('args');
+      assertNotSuggested('foo');
+      assertSuggestImportedClass('String');
+    });
+  }
+
+  test_ForEachStatement_loopVariable_type2() {
+    // DeclaredIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (S^ foo in args) {}}');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset - 1);
+      expect(request.replacementLength, 1);
+      assertNotSuggested('args');
+      assertNotSuggested('foo');
+      assertSuggestImportedClass('String');
+    });
+  }
+
   test_FormalParameterList() {
     // FormalParameterList MethodDeclaration
     addTestSource('''
@@ -1945,7 +2012,7 @@
     return computeFull((bool result) {
       expect(request.replacementOffset, completionOffset);
       expect(request.replacementLength, 0);
-      var f = assertSuggestLocalFunction('foo', 'String', false);
+      var f = assertSuggestLocalFunction('foo', 'String', deprecated: false);
       if (f != null) {
         expect(f.element.isPrivate, isFalse);
       }
@@ -1956,6 +2023,22 @@
     });
   }
 
+  test_IfStatement() {
+    // SimpleIdentifier  IfStatement
+    addTestSource('''
+      class A {var b; X _c; foo() {A a; if (true) ^}}''');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertSuggestLocalField('b', null);
+      assertSuggestLocalField('_c', 'X');
+      assertSuggestImportedClass('Object');
+      assertSuggestLocalClass('A');
+      assertNotSuggested('==');
+    });
+  }
+
   test_IfStatement_condition() {
     // SimpleIdentifier  IfStatement  Block  BlockFunctionBody
     addTestSource('''
@@ -1972,6 +2055,38 @@
     });
   }
 
+  test_IfStatement_empty() {
+    // SimpleIdentifier  IfStatement
+    addTestSource('''
+      class A {var b; X _c; foo() {A a; if (^) something}}''');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertSuggestLocalField('b', null);
+      assertSuggestLocalField('_c', 'X');
+      assertSuggestImportedClass('Object');
+      assertSuggestLocalClass('A');
+      assertNotSuggested('==');
+    });
+  }
+
+  test_IfStatement_invocation() {
+    // SimpleIdentifier  PrefixIdentifier  IfStatement
+    addTestSource('''
+      main() {var a; if (a.^) something}''');
+    computeFast();
+    return computeFull((bool result) {
+      expect(request.replacementOffset, completionOffset);
+      expect(request.replacementLength, 0);
+      assertSuggestInvocationMethod('toString', 'Object', 'String');
+      //TODO (danrubel) type for '_c' should be 'X' not null
+      assertNotSuggested('Object');
+      assertNotSuggested('A');
+      assertNotSuggested('==');
+    });
+  }
+
   test_ImportDirective_dart() {
     // SimpleStringLiteral  ImportDirective
     addTestSource('''
@@ -1983,6 +2098,54 @@
     });
   }
 
+  test_IndexExpression() {
+    // ExpressionStatement  Block
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
+    addTestSource('''
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} f[^]}}''');
+    computeFast();
+    return computeFull((bool result) {
+      assertNotSuggested('x');
+      assertSuggestLocalVariable('f', null);
+      assertSuggestLocalMethod('foo', 'C', null);
+      assertSuggestLocalClass('C');
+      assertSuggestLocalFunction('F2', null);
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      assertSuggestImportedClass('A');
+      assertSuggestImportedFunction('F1', null);
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
+    });
+  }
+
+  test_IndexExpression2() {
+    // SimpleIdentifier IndexExpression ExpressionStatement  Block
+    addSource('/testA.dart', '''
+      int T1;
+      F1() { }
+      class A {int x;}''');
+    addTestSource('''
+      import "/testA.dart";
+      int T2;
+      F2() { }
+      class B {int x;}
+      class C {foo(){var f; {var x;} f[T^]}}''');
+    computeFast();
+    return computeFull((bool result) {
+      // top level results are partially filtered based on first char
+      assertSuggestLocalTopLevelVar('T2', 'int');
+      // TODO (danrubel) getter is being suggested instead of top level var
+      //assertSuggestImportedTopLevelVar('T1', 'int');
+    });
+  }
+
   test_InstanceCreationExpression_imported() {
     // SimpleIdentifier  TypeName  ConstructorName  InstanceCreationExpression
     addSource('/testA.dart', '''
@@ -2189,8 +2352,8 @@
       CompletionSuggestion getterF = assertSuggestLocalGetter(
           'f',
           'X',
-          relevance: COMPLETION_RELEVANCE_LOW,
-          isDeprecated: true);
+          relevance: DART_RELEVANCE_LOW,
+          deprecated: true);
       if (getterF != null) {
         expect(getterF.element.isDeprecated, isTrue);
         expect(getterF.element.isPrivate, isFalse);
@@ -2218,8 +2381,8 @@
       CompletionSuggestion getterF = assertSuggestLocalField(
           'f',
           'X',
-          relevance: COMPLETION_RELEVANCE_LOW,
-          isDeprecated: true);
+          relevance: DART_RELEVANCE_LOW,
+          deprecated: true);
       if (getterF != null) {
         expect(getterF.element.isDeprecated, isTrue);
         expect(getterF.element.isPrivate, isFalse);
@@ -2246,8 +2409,8 @@
           'a',
           'A',
           'Z',
-          relevance: COMPLETION_RELEVANCE_LOW,
-          isDeprecated: true);
+          relevance: DART_RELEVANCE_LOW,
+          deprecated: true);
       if (methodA != null) {
         expect(methodA.element.isDeprecated, isTrue);
         expect(methodA.element.isPrivate, isFalse);
diff --git a/pkg/analysis_server/test/services/completion/imported_computer_test.dart b/pkg/analysis_server/test/services/completion/imported_computer_test.dart
index 9c20f67..d67c2d8 100644
--- a/pkg/analysis_server/test/services/completion/imported_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_computer_test.dart
@@ -107,10 +107,30 @@
 
   @override
   CompletionSuggestion assertSuggestImportedField(String name, String type,
-      [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+      {int relevance: DART_RELEVANCE_INHERITED_FIELD}) {
     return assertSuggestField(name, type, relevance: relevance);
   }
 
+  CompletionSuggestion assertSuggestImportedGetter(String name,
+      String returnType, {int relevance: DART_RELEVANCE_INHERITED_ACCESSOR}) {
+    return assertSuggestGetter(name, returnType, relevance: relevance);
+  }
+
+  CompletionSuggestion assertSuggestImportedMethod(String name,
+      String declaringType, String returnType, {int relevance:
+      DART_RELEVANCE_INHERITED_METHOD}) {
+    return assertSuggestMethod(
+        name,
+        declaringType,
+        returnType,
+        relevance: relevance);
+  }
+
+  CompletionSuggestion assertSuggestImportedSetter(String name, {int relevance:
+      DART_RELEVANCE_INHERITED_ACCESSOR}) {
+    return assertSuggestSetter(name, relevance);
+  }
+
   bool isCached(List<CompletionSuggestion> suggestions, String completion) =>
       suggestions.any((CompletionSuggestion s) => s.completion == completion);
 
@@ -349,7 +369,8 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+      CompletionSuggestion suggestion =
+          assertSuggestImportedMethod('m', 'A', 'void');
       expect(suggestion.parameterNames, hasLength(2));
       expect(suggestion.parameterNames[0], 'x');
       expect(suggestion.parameterTypes[0], 'dynamic');
@@ -373,7 +394,8 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+      CompletionSuggestion suggestion =
+          assertSuggestImportedMethod('m', 'A', 'void');
       expect(suggestion.parameterNames, hasLength(2));
       expect(suggestion.parameterNames[0], 'x');
       expect(suggestion.parameterTypes[0], 'dynamic');
@@ -397,7 +419,8 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+      CompletionSuggestion suggestion =
+          assertSuggestImportedMethod('m', 'A', 'void');
       expect(suggestion.parameterNames, hasLength(2));
       expect(suggestion.parameterNames[0], 'x');
       expect(suggestion.parameterTypes[0], 'dynamic');
@@ -422,7 +445,8 @@
 ''');
     computeFast();
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+      CompletionSuggestion suggestion =
+          assertSuggestImportedMethod('m', 'A', 'void');
       expect(suggestion.parameterNames, isEmpty);
       expect(suggestion.parameterTypes, isEmpty);
       expect(suggestion.requiredParameterCount, 0);
@@ -443,7 +467,8 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+      CompletionSuggestion suggestion =
+          assertSuggestImportedMethod('m', 'A', 'void');
       expect(suggestion.parameterNames, hasLength(2));
       expect(suggestion.parameterNames[0], 'x');
       expect(suggestion.parameterTypes[0], 'dynamic');
@@ -467,7 +492,8 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+      CompletionSuggestion suggestion =
+          assertSuggestImportedMethod('m', 'A', 'void');
       expect(suggestion.parameterNames, hasLength(2));
       expect(suggestion.parameterNames[0], 'x');
       expect(suggestion.parameterTypes[0], 'dynamic');
@@ -500,7 +526,7 @@
 }
 ''');
     return computeFull((bool result) {
-      assertSuggestMethod('m', 'M2', 'void');
+      assertSuggestImportedMethod('m', 'M2', 'void');
     });
   }
 
@@ -564,7 +590,7 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestField('x', 'int');
+      CompletionSuggestion suggestion = assertSuggestImportedField('x', 'int');
       assertHasNoParameterInfo(suggestion);
     });
   }
@@ -582,7 +608,7 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestGetter('x', 'int');
+      CompletionSuggestion suggestion = assertSuggestImportedGetter('x', 'int');
       assertHasNoParameterInfo(suggestion);
     });
   }
@@ -600,7 +626,7 @@
 }
 ''');
     return computeFull((bool result) {
-      CompletionSuggestion suggestion = assertSuggestSetter('x');
+      CompletionSuggestion suggestion = assertSuggestImportedSetter('x');
       assertHasNoParameterInfo(suggestion);
     });
   }
diff --git a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart b/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
index ddfb327..6b9886b 100644
--- a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
@@ -25,7 +25,7 @@
 
   @override
   CompletionSuggestion assertSuggestInvocationField(String name, String type,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
     return assertSuggestField(
         name,
         type,
@@ -132,6 +132,41 @@
     });
   }
 
+  test_local() {
+    addTestSource('foo() {String x = "bar"; x.^}');
+    return computeFull((bool result) {
+      assertSuggestGetter('length', 'int');
+    });
+  }
+
+  test_local_is() {
+    addTestSource('foo() {var x; if (x is String) x.^}');
+    return computeFull((bool result) {
+      assertSuggestGetter('length', 'int');
+    });
+  }
+
+  test_local_propogatedType() {
+    addTestSource('foo() {var x = "bar"; x.^}');
+    return computeFull((bool result) {
+      assertSuggestGetter('length', 'int');
+    });
+  }
+
+  test_param() {
+    addTestSource('foo(String x) {x.^}');
+    return computeFull((bool result) {
+      assertSuggestGetter('length', 'int');
+    });
+  }
+
+  test_param_is() {
+    addTestSource('foo(x) {if (x is String) x.^}');
+    return computeFull((bool result) {
+      assertSuggestGetter('length', 'int');
+    });
+  }
+
   test_method_parameters_mixed_required_and_named() {
     addTestSource('''
 class C {
diff --git a/pkg/analysis_server/test/services/completion/keyword_computer_test.dart b/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
index 9075d36..c51d186 100644
--- a/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
@@ -22,7 +22,7 @@
 class KeywordComputerTest extends AbstractCompletionTest {
 
   void assertSuggestKeywords(Iterable<Keyword> expectedKeywords, [int relevance
-      = COMPLETION_RELEVANCE_DEFAULT]) {
+      = DART_RELEVANCE_KEYWORD]) {
     Set<Keyword> actualKeywords = new Set<Keyword>();
     request.suggestions.forEach((CompletionSuggestion s) {
       if (s.kind == CompletionSuggestionKind.KEYWORD) {
@@ -76,7 +76,7 @@
             Keyword.FINAL,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_after_class2() {
@@ -90,7 +90,7 @@
             Keyword.FINAL,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_after_import() {
@@ -107,7 +107,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_after_import2() {
@@ -124,7 +124,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_before_import() {
@@ -132,7 +132,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.EXPORT, Keyword.IMPORT, Keyword.LIBRARY, Keyword.PART],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class() {
@@ -140,7 +140,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.EXTENDS, Keyword.IMPLEMENTS],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class2() {
@@ -148,7 +148,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.EXTENDS, Keyword.IMPLEMENTS],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class3() {
@@ -156,7 +156,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.EXTENDS, Keyword.IMPLEMENTS],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class_extends() {
@@ -164,7 +164,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.IMPLEMENTS, Keyword.WITH],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class_extends2() {
@@ -172,7 +172,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.IMPLEMENTS, Keyword.WITH],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class_extends3() {
@@ -180,7 +180,7 @@
     expect(computeFast(), isTrue);
     assertSuggestKeywords(
         [Keyword.IMPLEMENTS, Keyword.WITH],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class_extends_name() {
@@ -192,7 +192,7 @@
   test_class_implements() {
     addTestSource('class A ^ implements foo');
     expect(computeFast(), isTrue);
-    assertSuggestKeywords([Keyword.EXTENDS], COMPLETION_RELEVANCE_HIGH);
+    assertSuggestKeywords([Keyword.EXTENDS], DART_RELEVANCE_HIGH);
   }
 
   test_class_implements2() {
@@ -201,7 +201,7 @@
     // TODO (danrubel) refinement: don't suggest implements
     assertSuggestKeywords(
         [Keyword.EXTENDS, Keyword.IMPLEMENTS],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class_implements3() {
@@ -210,7 +210,7 @@
     // TODO (danrubel) refinement: don't suggest implements
     assertSuggestKeywords(
         [Keyword.EXTENDS, Keyword.IMPLEMENTS],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_class_implements_name() {
@@ -228,19 +228,19 @@
   test_class_with() {
     addTestSource('class A extends foo with bar ^');
     expect(computeFast(), isTrue);
-    assertSuggestKeywords([Keyword.IMPLEMENTS], COMPLETION_RELEVANCE_HIGH);
+    assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
   }
 
   test_class_with2() {
     addTestSource('class A extends foo with bar i^');
     expect(computeFast(), isTrue);
-    assertSuggestKeywords([Keyword.IMPLEMENTS], COMPLETION_RELEVANCE_HIGH);
+    assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
   }
 
   test_class_with3() {
     addTestSource('class A extends foo with bar i^ { }');
     expect(computeFast(), isTrue);
-    assertSuggestKeywords([Keyword.IMPLEMENTS], COMPLETION_RELEVANCE_HIGH);
+    assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
   }
 
   test_class_with_name() {
@@ -264,7 +264,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_function_body() {
@@ -350,7 +350,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_library_name() {
@@ -405,7 +405,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_partial_class() {
@@ -423,7 +423,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   test_partial_class2() {
@@ -440,7 +440,7 @@
             Keyword.PART,
             Keyword.TYPEDEF,
             Keyword.VAR],
-        COMPLETION_RELEVANCE_HIGH);
+        DART_RELEVANCE_HIGH);
   }
 
   void _appendKeywords(StringBuffer msg, Iterable<Keyword> keywords) {
diff --git a/pkg/analysis_server/test/services/completion/local_computer_test.dart b/pkg/analysis_server/test/services/completion/local_computer_test.dart
index 86b54ab..433ff77 100644
--- a/pkg/analysis_server/test/services/completion/local_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_computer_test.dart
@@ -22,7 +22,7 @@
 
   @override
   CompletionSuggestion assertSuggestLocalClass(String name, {int relevance:
-      COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
     return assertSuggestClass(
         name,
         relevance: relevance,
@@ -30,35 +30,108 @@
   }
 
   @override
+  CompletionSuggestion assertSuggestLocalClassTypeAlias(String name,
+      {int relevance: DART_RELEVANCE_DEFAULT}) {
+    return assertSuggestClassTypeAlias(name, relevance);
+  }
+
+  @override
   CompletionSuggestion assertSuggestLocalField(String name, String type,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_LOCAL_FIELD, bool deprecated: false}) {
     return assertSuggestField(
         name,
         type,
         relevance: relevance,
-        isDeprecated: isDeprecated);
+        isDeprecated: deprecated);
+  }
+
+  @override
+  CompletionSuggestion assertSuggestLocalFunction(String name,
+      String returnType, {bool deprecated: false, int relevance:
+      DART_RELEVANCE_LOCAL_FUNCTION}) {
+    return assertSuggestFunction(name, returnType, deprecated, relevance);
+  }
+
+  @override
+  CompletionSuggestion assertSuggestLocalFunctionTypeAlias(String name,
+      String returnType, {bool deprecated: false, int relevance:
+      DART_RELEVANCE_DEFAULT}) {
+    return assertSuggestFunctionTypeAlias(
+        name,
+        returnType,
+        deprecated,
+        relevance);
   }
 
   @override
   CompletionSuggestion assertSuggestLocalGetter(String name, String returnType,
-      {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      {int relevance: DART_RELEVANCE_LOCAL_ACCESSOR, bool deprecated: false}) {
     return assertSuggestGetter(
         name,
         returnType,
         relevance: relevance,
-        isDeprecated: isDeprecated);
+        isDeprecated: deprecated);
   }
 
   @override
   CompletionSuggestion assertSuggestLocalMethod(String name,
       String declaringType, String returnType, {int relevance:
-      COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+      DART_RELEVANCE_LOCAL_METHOD, bool deprecated: false}) {
     return assertSuggestMethod(
         name,
         declaringType,
         returnType,
         relevance: relevance,
-        isDeprecated: isDeprecated);
+        isDeprecated: deprecated);
+  }
+
+  @override
+  CompletionSuggestion assertSuggestLocalSetter(String name, {int relevance:
+      DART_RELEVANCE_LOCAL_ACCESSOR}) {
+    return assertSuggestSetter(name, relevance);
+  }
+
+  @override
+  CompletionSuggestion assertSuggestLocalTopLevelVar(String name,
+      String returnType, {int relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE}) {
+    return assertSuggestTopLevelVar(name, returnType, relevance);
+  }
+
+  @override
+  CompletionSuggestion assertSuggestLocalVariable(String name,
+      String returnType, {int relevance: DART_RELEVANCE_LOCAL_VARIABLE}) {
+    // Local variables should only be suggested by LocalComputer
+    CompletionSuggestion cs = assertSuggest(
+        name,
+        csKind: CompletionSuggestionKind.INVOCATION,
+        relevance: relevance);
+    expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+    Element element = cs.element;
+    expect(element, isNotNull);
+    expect(element.kind, equals(ElementKind.LOCAL_VARIABLE));
+    expect(element.name, equals(name));
+    expect(element.parameters, isNull);
+    expect(element.returnType, returnType != null ? returnType : 'dynamic');
+    assertHasNoParameterInfo(cs);
+    return cs;
+  }
+
+  CompletionSuggestion assertSuggestParameter(String name, String returnType,
+      {int relevance: DART_RELEVANCE_PARAMETER}) {
+    CompletionSuggestion cs = assertSuggest(
+        name,
+        csKind: CompletionSuggestionKind.INVOCATION,
+        relevance: relevance);
+    expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+    Element element = cs.element;
+    expect(element, isNotNull);
+    expect(element.kind, equals(ElementKind.PARAMETER));
+    expect(element.name, equals(name));
+    expect(element.parameters, isNull);
+    expect(
+        element.returnType,
+        equals(returnType != null ? returnType : 'dynamic'));
+    return cs;
   }
 
   fail_mixin_ordering() {
@@ -373,7 +446,7 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+    CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -391,7 +464,7 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+    CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -409,7 +482,7 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+    CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -427,7 +500,7 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+    CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
     expect(suggestion.parameterNames, isEmpty);
     expect(suggestion.parameterTypes, isEmpty);
     expect(suggestion.requiredParameterCount, 0);
@@ -442,7 +515,7 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+    CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -460,7 +533,7 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+    CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -480,7 +553,8 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+    CompletionSuggestion suggestion =
+        assertSuggestLocalMethod('m', 'A', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -500,7 +574,8 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+    CompletionSuggestion suggestion =
+        assertSuggestLocalMethod('m', 'A', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -520,7 +595,8 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+    CompletionSuggestion suggestion =
+        assertSuggestLocalMethod('m', 'A', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -540,7 +616,8 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+    CompletionSuggestion suggestion =
+        assertSuggestLocalMethod('m', 'A', 'void');
     expect(suggestion.parameterNames, isEmpty);
     expect(suggestion.parameterTypes, isEmpty);
     expect(suggestion.requiredParameterCount, 0);
@@ -557,7 +634,8 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+    CompletionSuggestion suggestion =
+        assertSuggestLocalMethod('m', 'A', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
@@ -577,7 +655,8 @@
 }
 ''');
     expect(computeFast(), isTrue);
-    CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+    CompletionSuggestion suggestion =
+        assertSuggestLocalMethod('m', 'A', 'void');
     expect(suggestion.parameterNames, hasLength(2));
     expect(suggestion.parameterNames[0], 'x');
     expect(suggestion.parameterTypes[0], 'dynamic');
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index 9e6d8e0..ce7a5ba 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -46,12 +46,30 @@
   void assertOpType({bool invocation: false, bool returnValue: false,
       bool typeNames: false, bool voidReturn: false, bool statementLabel: false,
       bool caseLabel: false}) {
-    expect(visitor.includeInvocationSuggestions, equals(invocation));
-    expect(visitor.includeReturnValueSuggestions, equals(returnValue));
-    expect(visitor.includeTypeNameSuggestions, equals(typeNames));
-    expect(visitor.includeVoidReturnSuggestions, equals(voidReturn));
-    expect(visitor.includeStatementLabelSuggestions, equals(statementLabel));
-    expect(visitor.includeCaseLabelSuggestions, equals(caseLabel));
+    expect(
+        visitor.includeInvocationSuggestions,
+        equals(invocation),
+        reason: 'invocation');
+    expect(
+        visitor.includeReturnValueSuggestions,
+        equals(returnValue),
+        reason: 'returnValue');
+    expect(
+        visitor.includeTypeNameSuggestions,
+        equals(typeNames),
+        reason: 'typeNames');
+    expect(
+        visitor.includeVoidReturnSuggestions,
+        equals(voidReturn),
+        reason: 'voidReturn');
+    expect(
+        visitor.includeStatementLabelSuggestions,
+        equals(statementLabel),
+        reason: 'statementLabel');
+    expect(
+        visitor.includeCaseLabelSuggestions,
+        equals(caseLabel),
+        reason: 'caseLabel');
   }
 
   test_Annotation() {
@@ -285,16 +303,34 @@
     assertOpType(returnValue: true, typeNames: true, voidReturn: true);
   }
 
-  test_ConditionalExpression_empty() {
-    // SimpleIdentifier  PrefixIdentifier  IfStatement
-    addTestSource('class A {foo() {A a; if (^) something}}');
+  test_ConditionalExpression_elseExpression() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addTestSource('class C {foo(){var f; {var x;} return a ? T1 : T^}}');
     assertOpType(returnValue: true, typeNames: true);
   }
 
-  test_ConditionalExpression_invocation() {
-    // SimpleIdentifier  PrefixIdentifier  IfStatement
-    addTestSource('main() {var a; if (a.^) something}');
-    assertOpType(invocation: true);
+  test_ConditionalExpression_elseExpression_empty() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addTestSource('class C {foo(){var f; {var x;} return a ? T1 : ^}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
+  test_ConditionalExpression_partial_thenExpression() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addTestSource('class C {foo(){var f; {var x;} return a ? T^}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
+  test_ConditionalExpression_partial_thenExpression_empty() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addTestSource('class C {foo(){var f; {var x;} return a ? ^}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
+  test_ConditionalExpression_thenExpression() {
+    // SimpleIdentifier  ConditionalExpression  ReturnStatement
+    addTestSource('class C {foo(){var f; {var x;} return a ? T^ : c}}');
+    assertOpType(returnValue: true, typeNames: true);
   }
 
   test_ConstructorName() {
@@ -340,6 +376,12 @@
     assertOpType(statementLabel: true, caseLabel: true);
   }
 
+  test_DefaultFormalParameter_named_expression() {
+    // DefaultFormalParameter FormalParameterList MethodDeclaration
+    addTestSource('class A {a(blat: ^) { }}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
   test_DoStatement() {
     // SimpleIdentifier  DoStatement  Block
     addTestSource('main() {do{} while(^x);}');
@@ -402,6 +444,42 @@
     assertOpType(returnValue: true, typeNames: true, voidReturn: true);
   }
 
+  test_ForEachStatement_iterable() {
+    // SimpleIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (int foo in ^) {}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
+  test_ForEachStatement_loopVariable() {
+    // SimpleIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (^ in args) {}}');
+    assertOpType(typeNames: true);
+  }
+
+  test_ForEachStatement_loopVariable_name() {
+    // DeclaredIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (String ^ in args) {}}');
+    assertOpType();
+  }
+
+  test_ForEachStatement_loopVariable_name2() {
+    // DeclaredIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (String f^ in args) {}}');
+    assertOpType();
+  }
+
+  test_ForEachStatement_loopVariable_type() {
+    // SimpleIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (^ foo in args) {}}');
+    assertOpType(typeNames: true);
+  }
+
+  test_ForEachStatement_loopVariable_type2() {
+    // DeclaredIdentifier  ForEachStatement  Block
+    addTestSource('main(args) {for (S^ foo in args) {}}');
+    assertOpType(typeNames: true);
+  }
+
   test_FormalParameterList() {
     // FormalParameterList MethodDeclaration
     addTestSource('class A {a(^) { }}');
@@ -453,6 +531,18 @@
     assertOpType(returnValue: true, typeNames: true);
   }
 
+  test_IfStatement_empty() {
+    // SimpleIdentifier  PrefixIdentifier  IfStatement
+    addTestSource('class A {foo() {A a; if (^) something}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
+  test_IfStatement_invocation() {
+    // SimpleIdentifier  PrefixIdentifier  IfStatement
+    addTestSource('main() {var a; if (a.^) something}');
+    assertOpType(invocation: true);
+  }
+
   test_ImplementsClause() {
     // ImplementsClause  ClassDeclaration
     addTestSource('class x implements ^\n{}');
@@ -467,6 +557,16 @@
     assertOpType();
   }
 
+  test_IndexExpression() {
+    addTestSource('class C {foo(){var f; {var x;} f[^]}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
+  test_IndexExpression2() {
+    addTestSource('class C {foo(){var f; {var x;} f[T^]}}');
+    assertOpType(returnValue: true, typeNames: true);
+  }
+
   test_InstanceCreationExpression_imported() {
     // SimpleIdentifier  TypeName  ConstructorName  InstanceCreationExpression
     addTestSource('class C {foo(){var f; {var x;} new ^}}');
@@ -476,19 +576,13 @@
   test_InstanceCreationExpression_keyword() {
     // InstanceCreationExpression  ExpressionStatement  Block
     addTestSource('class C {foo(){var f; {var x;} new^ }}');
-    assertOpType(
-        returnValue: true,
-        typeNames: true,
-        voidReturn: true);
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
   }
 
   test_InstanceCreationExpression_keyword2() {
     // InstanceCreationExpression  ExpressionStatement  Block
     addTestSource('class C {foo(){var f; {var x;} new^ C();}}');
-    assertOpType(
-        returnValue: true,
-        typeNames: true,
-        voidReturn: true);
+    assertOpType(returnValue: true, typeNames: true, voidReturn: true);
   }
 
   test_InterpolationExpression() {
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index e8ced6a..efe7091 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -768,6 +768,30 @@
 ''');
   }
 
+  test_singleExpression_inIfElseIf() {
+    indexTestUnit('''
+main(int p) {
+  if (p == 1) {
+    print(1);
+  } else if (p == 2) {
+    print(2);
+  }
+}
+''');
+    _createRefactoringForString('2');
+    // apply refactoring
+    return _assertSuccessfulRefactoring('''
+main(int p) {
+  var res = 2;
+  if (p == 1) {
+    print(1);
+  } else if (p == res) {
+    print(res);
+  }
+}
+''');
+  }
+
   test_singleExpression_inMethod() {
     indexTestUnit('''
 class A {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index fbd1d39..af7eb92 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1856,6 +1856,39 @@
   }
 
   @override
+  CompilationUnit ensureAnyResolvedDartUnit(Source source) {
+    SourceEntry sourceEntry = _cache.get(source);
+    if (sourceEntry is! DartEntry) {
+      return null;
+    }
+    DartEntry dartEntry = sourceEntry;
+    // Check if there is a resolved unit.
+    CompilationUnit unit = dartEntry.anyResolvedCompilationUnit;
+    if (unit != null) {
+      return unit;
+    }
+    // Invalidate the flushed RESOLVED_UNIT to force it eventually.
+    bool shouldBeScheduled = false;
+    List<Source> librariesContaining = dartEntry.containingLibraries;
+    for (Source librarySource in librariesContaining) {
+      if (dartEntry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) ==
+          CacheState.FLUSHED) {
+        dartEntry.setStateInLibrary(
+            DartEntry.RESOLVED_UNIT,
+            librarySource,
+            CacheState.INVALID);
+        shouldBeScheduled = true;
+      }
+    }
+    if (shouldBeScheduled) {
+      _workManager.add(source, SourcePriority.UNKNOWN);
+    }
+    // We cannot provide a resolved unit right now,
+    // but the future analysis will.
+    return null;
+  }
+
+  @override
   bool exists(Source source) {
     if (source == null) {
       return false;
@@ -2184,16 +2217,12 @@
             !_tryPoorMansIncrementalResolution(source, newContents)) {
           _sourceChanged(source);
         }
-        if (sourceEntry != null) {
-          sourceEntry.modificationTime =
-              _contentCache.getModificationStamp(source);
-          sourceEntry.setValue(SourceEntry.CONTENT, newContents);
-        }
+        sourceEntry.modificationTime =
+            _contentCache.getModificationStamp(source);
+        sourceEntry.setValue(SourceEntry.CONTENT, newContents);
       } else {
-        if (sourceEntry != null) {
-          sourceEntry.modificationTime =
-              _contentCache.getModificationStamp(source);
-        }
+        sourceEntry.modificationTime =
+            _contentCache.getModificationStamp(source);
       }
     } else if (originalContents != null) {
       _incrementalAnalysisCache =
@@ -2201,17 +2230,15 @@
       changed = newContents != originalContents;
       // We are removing the overlay for the file, check if the file's
       // contents is the same as it was in the overlay.
-      if (sourceEntry != null) {
-        try {
-          TimestampedData<String> fileContents = getContents(source);
-          String fileContentsData = fileContents.data;
-          if (fileContentsData == originalContents) {
-            sourceEntry.modificationTime = fileContents.modificationTime;
-            sourceEntry.setValue(SourceEntry.CONTENT, fileContentsData);
-            changed = false;
-          }
-        } catch (e) {
+      try {
+        TimestampedData<String> fileContents = getContents(source);
+        String fileContentsData = fileContents.data;
+        if (fileContentsData == originalContents) {
+          sourceEntry.modificationTime = fileContents.modificationTime;
+          sourceEntry.setValue(SourceEntry.CONTENT, fileContentsData);
+          changed = false;
         }
+      } catch (e) {
       }
       // If not the same content (e.g. the file is being closed without save),
       // then force analysis.
@@ -2226,6 +2253,31 @@
     return changed;
   }
 
+  /**
+   * Invalidates hints in the given [librarySource] and included parts.
+   */
+  void invalidateLibraryHints(Source librarySource) {
+    SourceEntry sourceEntry = _cache.get(librarySource);
+    if (sourceEntry is! DartEntry) {
+      return;
+    }
+    DartEntry dartEntry = sourceEntry;
+    // Prepare sources to invalidate hints in.
+    List<Source> sources = <Source>[librarySource];
+    sources.addAll(dartEntry.getValue(DartEntry.INCLUDED_PARTS));
+    // Invalidate hints.
+    for (Source source in sources) {
+      DartEntry dartEntry = _cache.get(source);
+      if (dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource) ==
+          CacheState.VALID) {
+        dartEntry.setStateInLibrary(
+            DartEntry.HINTS,
+            librarySource,
+            CacheState.INVALID);
+      }
+    }
+  }
+
   @override
   bool isClientLibrary(Source librarySource) {
     SourceEntry sourceEntry = _getReadableSourceEntry(librarySource);
@@ -5043,19 +5095,9 @@
     if (libraryElement == null) {
       return false;
     }
-    // prepare the existing library units
-    Map<Source, CompilationUnit> units = <Source, CompilationUnit>{};
-    for (CompilationUnitElement unitElement in libraryElement.units) {
-      Source unitSource = unitElement.source;
-      CompilationUnit unit =
-          getResolvedCompilationUnit2(unitSource, librarySource);
-      if (unit == null) {
-        return false;
-      }
-      units[unitSource] = unit;
-    }
     // prepare the existing unit
-    CompilationUnit oldUnit = units[unitSource];
+    CompilationUnit oldUnit =
+        getResolvedCompilationUnit2(unitSource, librarySource);
     if (oldUnit == null) {
       return false;
     }
@@ -5063,9 +5105,9 @@
     Stopwatch perfCounter = new Stopwatch()..start();
     PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
         typeProvider,
-        units,
         unitSource,
         dartEntry,
+        oldUnit,
         analysisOptions.incrementalApi);
     bool success = resolver.resolve(newCode);
     AnalysisEngine.instance.instrumentationService.logPerformance(
@@ -5083,14 +5125,13 @@
       incrementalResolutionValidation_lastUnit = oldUnit;
       return false;
     }
-    // prepare notices
-    units.forEach((Source source, CompilationUnit unit) {
-      DartEntry dartEntry = _cache.get(source);
-      LineInfo lineInfo = getLineInfo(source);
-      ChangeNoticeImpl notice = _getNotice(source);
-      notice.resolvedDartUnit = unit;
+    // prepare notice
+    {
+      LineInfo lineInfo = getLineInfo(unitSource);
+      ChangeNoticeImpl notice = _getNotice(unitSource);
+      notice.resolvedDartUnit = oldUnit;
       notice.setErrors(dartEntry.allErrors, lineInfo);
-    });
+    }
     // OK
     return true;
   }
@@ -9613,7 +9654,6 @@
         LibraryElement library = element.library;
         if (library != null) {
           IncrementalResolver resolver = new IncrementalResolver(
-              <Source, CompilationUnit>{},
               element,
               cache.offset,
               cache.oldLength,
@@ -9703,6 +9743,13 @@
   CompilationUnit computeResolvableCompilationUnit(Source source);
 
   /**
+   * Return any resolved [CompilationUnit] for the given [source] if not
+   * flushed, otherwise return `null` and ensures that the [CompilationUnit]
+   * will be eventually returned to the client from [performAnalysisTask].
+   */
+  CompilationUnit ensureAnyResolvedDartUnit(Source source);
+
+  /**
    * Return context that owns the given source.
    *
    * @param source the source whose context is to be returned
@@ -9725,7 +9772,7 @@
    * is the updated contents.  If [notify] is true, a source changed event is
    * triggered.
    *
-   * Normally it should not be necessary for clinets to call this function,
+   * Normally it should not be necessary for clients to call this function,
    * since it will be automatically invoked in response to a call to
    * [applyChanges] or [setContents].  However, if this analysis context is
    * sharing its content cache with other contexts, then the client must
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 50bba03..06026b3 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -7,6 +7,8 @@
 import "dart:math" as math;
 import 'dart:collection';
 
+import 'package:analyzer/src/generated/static_type_analyzer.dart';
+
 import 'ast.dart';
 import 'constant.dart';
 import 'element.dart';
@@ -5885,10 +5887,9 @@
       }
     }
     DartType staticReturnType = getStaticType(returnExpression);
-    if (staticReturnType != null &&
-        _enclosingFunction.isAsynchronous &&
-        staticReturnType.element != _typeProvider.futureType.element) {
-      return _typeProvider.futureType.substitute4(<DartType>[staticReturnType]);
+    if (staticReturnType != null && _enclosingFunction.isAsynchronous) {
+      return _typeProvider.futureType.substitute4(
+          <DartType>[StaticTypeAnalyzer.flattenFutures(_typeProvider, staticReturnType)]);
     }
     return staticReturnType;
   }
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 152bb47..038d0f0 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -787,11 +787,6 @@
  */
 class IncrementalResolver {
   /**
-   * All resolved units of the [_definingLibrary].
-   */
-  final Map<Source, CompilationUnit> _units;
-
-  /**
    * The element of the compilation unit being resolved.
    */
   final CompilationUnitElement _definingUnit;
@@ -854,7 +849,7 @@
    * Initialize a newly created incremental resolver to resolve a node in the
    * given source in the given library.
    */
-  IncrementalResolver(this._units, this._definingUnit, this._updateOffset,
+  IncrementalResolver(this._definingUnit, this._updateOffset,
       this._updateEndOld, this._updateEndNew) {
     _updateDelta = _updateEndNew - _updateEndOld;
     _definingLibrary = _definingUnit.library;
@@ -887,7 +882,7 @@
       _resolveReferences(rootNode);
       // verify
       _verify(rootNode);
-      _generateHints(rootNode);
+      _context.invalidateLibraryHints(_librarySource);
       _generateLints(rootNode);
       // update entry errors
       _updateEntry();
@@ -978,33 +973,6 @@
     throw new AnalysisException("Cannot resolve node: no resolvable node");
   }
 
-  void _generateHints(AstNode node) {
-    LoggingTimer timer = logger.startTimer();
-    try {
-      RecordingErrorListener errorListener = new RecordingErrorListener();
-      // prepare a list of the library units
-      List<CompilationUnit> units;
-      {
-        CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
-        _units[_source] = unit;
-        units = _units.values.toList();
-      }
-      // run the generator
-      AnalysisContext analysisContext = _definingLibrary.context;
-      HintGenerator hintGenerator =
-          new HintGenerator(units, analysisContext, errorListener);
-      hintGenerator.generateForLibrary();
-      // remember hints
-      for (Source source in _units.keys) {
-        List<AnalysisError> hints = errorListener.getErrorsForSource(source);
-        DartEntry entry = _context.getReadableSourceEntryOrNull(source);
-        entry.setValueInLibrary(DartEntry.HINTS, _librarySource, hints);
-      }
-    } finally {
-      timer.stop('generate hints');
-    }
-  }
-
   void _generateLints(AstNode node) {
     LoggingTimer timer = logger.startTimer();
     try {
@@ -1189,9 +1157,9 @@
 
 class PoorMansIncrementalResolver {
   final TypeProvider _typeProvider;
-  final Map<Source, CompilationUnit> _units;
   final Source _unitSource;
   final DartEntry _entry;
+  final CompilationUnit _oldUnit;
   CompilationUnitElement _unitElement;
 
   int _updateOffset;
@@ -1202,26 +1170,25 @@
   List<AnalysisError> _newScanErrors = <AnalysisError>[];
   List<AnalysisError> _newParseErrors = <AnalysisError>[];
 
-  PoorMansIncrementalResolver(this._typeProvider, this._units, this._unitSource,
-      this._entry, bool resolveApiChanges) {
+  PoorMansIncrementalResolver(this._typeProvider, this._unitSource,
+      this._entry, this._oldUnit, bool resolveApiChanges) {
     _resolveApiChanges = resolveApiChanges;
   }
 
   /**
-   * Attempts to update [oldUnit] to the state corresponding to [newCode].
+   * Attempts to update [_oldUnit] to the state corresponding to [newCode].
    * Returns `true` if success, or `false` otherwise.
-   * The [oldUnit] might be damaged.
+   * The [_oldUnit] might be damaged.
    */
   bool resolve(String newCode) {
     logger.enter('diff/resolve $_unitSource');
     try {
       // prepare old unit
-      CompilationUnit oldUnit = _units[_unitSource];
-      if (!_areCurlyBracketsBalanced(oldUnit.beginToken)) {
+      if (!_areCurlyBracketsBalanced(_oldUnit.beginToken)) {
         logger.log('Unbalanced number of curly brackets in the old unit.');
         return false;
       }
-      _unitElement = oldUnit.element;
+      _unitElement = _oldUnit.element;
       // prepare new unit
       CompilationUnit newUnit = _parseUnit(newCode);
       if (!_areCurlyBracketsBalanced(newUnit.beginToken)) {
@@ -1230,9 +1197,9 @@
       }
       // find difference
       _TokenPair firstPair =
-          _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken);
+          _findFirstDifferentToken(_oldUnit.beginToken, newUnit.beginToken);
       _TokenPair lastPair =
-          _findLastDifferentToken(oldUnit.endToken, newUnit.endToken);
+          _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken);
       if (firstPair != null && lastPair != null) {
         int firstOffsetOld = firstPair.oldToken.offset;
         int firstOffsetNew = firstPair.newToken.offset;
@@ -1248,10 +1215,10 @@
           _updateOffset = beginOffsetOld - 1;
           _updateEndOld = endOffsetOld;
           _updateEndNew = endOffsetNew;
-          _updateDelta = newUnit.length - oldUnit.length;
+          _updateDelta = newUnit.length - _oldUnit.length;
           // A Dart documentation comment change.
           if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) {
-            bool success = _resolveComment(oldUnit, newUnit, firstPair);
+            bool success = _resolveComment(_oldUnit, newUnit, firstPair);
             logger.log('Documentation comment resolved: $success');
             return success;
           }
@@ -1261,7 +1228,6 @@
             _shiftTokens(firstPair.oldToken);
             {
               IncrementalResolver incrementalResolver = new IncrementalResolver(
-                  _units,
                   _unitElement,
                   _updateOffset,
                   _updateEndOld,
@@ -1277,7 +1243,7 @@
         }
         // Find nodes covering the "old" and "new" token ranges.
         AstNode oldNode =
-            _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld);
+            _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld);
         AstNode newNode =
             _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew);
         logger.log(() => 'oldNode: $oldNode');
@@ -1325,7 +1291,7 @@
           Token oldBeginToken = _getBeginTokenNotComment(oldNode);
           Token newBeginToken = _getBeginTokenNotComment(newNode);
           if (oldBeginToken.previous.type == TokenType.EOF) {
-            oldUnit.beginToken = newBeginToken;
+            _oldUnit.beginToken = newBeginToken;
           } else {
             oldBeginToken.previous.setNext(newBeginToken);
           }
@@ -1334,7 +1300,6 @@
         }
         // perform incremental resolution
         IncrementalResolver incrementalResolver = new IncrementalResolver(
-            _units,
             _unitElement,
             _updateOffset,
             _updateEndOld,
@@ -1402,7 +1367,6 @@
     NodeReplacer.replace(oldComment, newComment);
     // update elements
     IncrementalResolver incrementalResolver = new IncrementalResolver(
-        _units,
         _unitElement,
         _updateOffset,
         _updateEndOld,
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 99a51ce..7b461df 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -175,6 +175,34 @@
   }
 
   /**
+   * The Dart Language Specification, 16.29 (Await Expressions):
+   *
+   *   Let flatten(T) = flatten(S) if T = Future<S>, and T otherwise.  The
+   *   static type of [the expression "await e"] is flatten(T) where T is the
+   *   static type of e.
+   */
+  @override
+  Object visitAwaitExpression(AwaitExpression node) {
+    DartType staticExpressionType = _getStaticType(node.expression);
+    if (staticExpressionType == null) {
+      // TODO(brianwilkerson) Determine whether this can still happen.
+      staticExpressionType = _dynamicType;
+    }
+    DartType staticType = flattenFutures(_typeProvider, staticExpressionType);
+    _recordStaticType(node, staticType);
+    DartType propagatedExpressionType = node.expression.propagatedType;
+    if (propagatedExpressionType != null) {
+      DartType propagatedType =
+          flattenFutures(_typeProvider, propagatedExpressionType);
+      if (propagatedType != null &&
+          propagatedType.isMoreSpecificThan(staticType)) {
+        _recordPropagatedType(node, propagatedType);
+      }
+    }
+    return null;
+  }
+
+  /**
    * The Dart Language Specification, 12.20: <blockquote>The static type of a logical boolean
    * expression is `bool`.</blockquote>
    *
@@ -1772,6 +1800,19 @@
   }
 
   /**
+   * Implements the function "flatten" defined in the spec: "Let flatten(T) =
+   * flatten(S) if T = Future<S>, and T otherwise."
+   */
+  static DartType flattenFutures(TypeProvider typeProvider, DartType type) {
+    if (type is InterfaceType &&
+        type.element == typeProvider.futureType.element &&
+        type.typeArguments.length > 0) {
+      return flattenFutures(typeProvider, type.typeArguments[0]);
+    }
+    return type;
+  }
+
+  /**
    * Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
    * implement those tags.
    *
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index ff1e30a..f95e230 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -507,7 +507,13 @@
   }
 
   visitBlockFunctionBody(BlockFunctionBody node) {
-    token(node.keyword, followedBy: nonBreakingSpace);
+    // sync[*] or async[*]
+    token(node.keyword);
+    token(node.star);
+    if (node.keyword != null) {
+      nonBreakingSpace();
+    }
+
     visit(node.block);
   }
 
@@ -836,6 +842,7 @@
   }
 
   visitForEachStatement(ForEachStatement node) {
+    token(node.awaitKeyword, followedBy: nonBreakingSpace);
     token(node.forKeyword);
     space();
     token(node.leftParenthesis);
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index a30c5f6..0089eb8 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -6048,6 +6048,11 @@
     fail("Unexpected invocation of dispose");
   }
   @override
+  CompilationUnit ensureAnyResolvedDartUnit(Source source) {
+    fail("Unexpected invocation of ensureAnyResolvedDartUnit");
+    return null;
+  }
+  @override
   bool exists(Source source) {
     fail("Unexpected invocation of exists");
     return false;
@@ -6210,6 +6215,7 @@
   void setContents(Source source, String contents) {
     fail("Unexpected invocation of setContents");
   }
+
   @override
   void visitCacheItems(void callback(Source source, SourceEntry dartEntry,
       DataDescriptor rowDesc, CacheState state)) {
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 90106a9..5e41ef6 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -2506,13 +2506,14 @@
     int updateOffset = edit.offset;
     int updateEndOld = updateOffset + edit.length;
     int updateOldNew = updateOffset + edit.replacement.length;
-    IncrementalResolver resolver =
-        new IncrementalResolver(<Source, CompilationUnit>{
-      source: newUnit
-    }, unit.element, updateOffset, updateEndOld, updateOldNew);
+    IncrementalResolver resolver = new IncrementalResolver(
+        unit.element,
+        updateOffset,
+        updateEndOld,
+        updateOldNew);
     bool success = resolver.resolve(newNode);
     expect(success, isTrue);
-    List<AnalysisError> newErrors = analysisContext.getErrors(source).errors;
+    List<AnalysisError> newErrors = analysisContext.computeErrors(source);
     // resolve "newCode" from scratch
     CompilationUnit fullNewUnit;
     {
@@ -3211,8 +3212,13 @@
 //  a._foo();
 }
 ''');
+    // no hints right now, because we delay hints computing
+    {
+      List<AnalysisError> errors = analysisContext.getErrors(source).errors;
+      expect(errors, isEmpty);
+    }
     // a new hint should be added
-    List<AnalysisError> errors = analysisContext.getErrors(source).errors;
+    List<AnalysisError> errors = analysisContext.computeErrors(source);
     expect(errors, hasLength(1));
     expect(errors[0].errorCode.type, ErrorType.HINT);
     // the same hint should be reported using a ChangeNotice
@@ -3458,7 +3464,7 @@
     _resetWithIncremental(true);
     analysisContext2.setContents(source, newCode);
     CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
-    List<AnalysisError> newErrors = analysisContext.getErrors(source).errors;
+    List<AnalysisError> newErrors = analysisContext.computeErrors(source);
     // check for expected failure
     if (!expectedSuccess) {
       expect(newUnit.element, isNot(same(oldUnitElement)));
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 680045a..3238e50 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -487,6 +487,19 @@
     verify([source]);
   }
 
+  void test_async_return_flattens_futures() {
+    Source source = addSource('''
+import 'dart:async';
+Future<int> f() async {
+  return g();
+}
+Future<Future<int>> g() => null;
+''');
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_async_with_return() {
     Source source = addSource('''
 f() async {
@@ -540,6 +553,32 @@
     verify([source]);
   }
 
+  void test_await_flattened() {
+    Source source = addSource('''
+import 'dart:async';
+Future<Future<int>> ffi() => null;
+f() async {
+  int b = await ffi();
+}
+''');
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  void test_await_simple() {
+    Source source = addSource('''
+import 'dart:async';
+Future<int> fi() => null;
+f() async {
+  int a = await fi();
+}
+''');
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_awaitInWrongContext_async() {
     Source source = addSource(r'''
 f(x, y) async {
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 17c8e69..b2f48d0 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -9851,6 +9851,30 @@
     _listener.assertNoErrors();
   }
 
+  void test_visitAwaitExpression_flattened() {
+    // await e, where e has type Future<Future<int>>
+    InterfaceType intType = _typeProvider.intType;
+    InterfaceType futureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[intType]);
+    InterfaceType futureFutureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[futureIntType]);
+    Expression node =
+        AstFactory.awaitExpression(_resolvedVariable(futureFutureIntType, 'e'));
+    expect(_analyze(node), same(intType));
+    _listener.assertNoErrors();
+  }
+
+  void test_visitAwaitExpression_simple() {
+    // await e, where e has type Future<int>
+    InterfaceType intType = _typeProvider.intType;
+    InterfaceType futureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[intType]);
+    Expression node =
+        AstFactory.awaitExpression(_resolvedVariable(futureIntType, 'e'));
+    expect(_analyze(node), same(intType));
+    _listener.assertNoErrors();
+  }
+
   void test_visitBinaryExpression_equals() {
     // 2 == 3
     Expression node = AstFactory.binaryExpression(
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index bf70201..c0ea73e 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -54,6 +54,32 @@
     assertErrors(source, [StaticWarningCode.AMBIGUOUS_IMPORT]);
   }
 
+  void test_await_flattened() {
+    Source source = addSource('''
+import 'dart:async';
+Future<Future<int>> ffi() => null;
+f() async {
+  Future<int> b = await ffi(); // Warning: int not assignable to Future<int>
+}
+''');
+    resolve(source);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+    verify([source]);
+  }
+
+  void test_await_simple() {
+    Source source = addSource('''
+import 'dart:async';
+Future<int> fi() => null;
+f() async {
+  String a = await fi(); // Warning: int not assignable to String
+}
+''');
+    resolve(source);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+    verify([source]);
+  }
+
   void test_expectedOneListTypeArgument() {
     Source source = addSource(r'''
 main() {
diff --git a/pkg/analyzer/test/services/data/cu_tests.data b/pkg/analyzer/test/services/data/cu_tests.data
index 9f9e803..0c5ae6b 100644
--- a/pkg/analyzer/test/services/data/cu_tests.data
+++ b/pkg/analyzer/test/services/data/cu_tests.data
@@ -308,18 +308,16 @@
       this.c0123456789012345678901234, this.d0123456789012345678901234);
 }
 >>>
-main() async {
-}
-<<<
-main() async {
-}
->>>
-main()  async  => 0;
-<<<
-main() async => 0;
->>>
 enum Foo { BAR, BAZ }
 <<<
 enum Foo {
   BAR, BAZ
 }
+>>>
+get x sync* {}
+<<<
+get x sync* {}
+>>>
+get x async* {}
+<<<
+get x async* {}
\ No newline at end of file
diff --git a/pkg/analyzer/test/services/data/stmt_tests.data b/pkg/analyzer/test/services/data/stmt_tests.data
index d1cf4cc..ef98247 100644
--- a/pkg/analyzer/test/services/data/stmt_tests.data
+++ b/pkg/analyzer/test/services/data/stmt_tests.data
@@ -205,3 +205,59 @@
       00000000000000000000000000000000000000000000000000000000000,
       111);
 }
+>>>
+foo() async => 42;
+<<<
+foo() async => 42;
+>>>
+main() async {
+  await window.animationFrame;
+}
+<<<
+main() async {
+  await window.animationFrame;
+}
+>>>
+main() async* {
+  await window.animationFrame;
+}
+<<<
+main() async* {
+  await window.animationFrame;
+}
+>>>
+foo() async* {
+  var elements = await _post('elements', by);
+  int i = 0;
+  for (var element in elements) {
+    yield new WebElement._(driver, element['ELEMENT'], this, by, i);
+    i++;
+  }
+}
+<<<
+foo() async* {
+  var elements = await _post('elements', by);
+  int i = 0;
+  for (var element in elements) {
+    yield new WebElement._(driver, element['ELEMENT'], this, by, i);
+    i++;
+  }
+}
+>>>
+b06a() async { await for (var o in st) {} } 
+<<<
+b06a() async {
+  await for (var o in st) {}
+}
+>>>
+b07a() sync* { yield 0; }
+<<<
+b07a() sync* {
+  yield 0;
+}
+>>>
+b08a() sync* { yield* []; } 
+<<<
+b08a() sync* {
+  yield* [];
+}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 173f421..a99134f 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -2395,6 +2395,22 @@
 
   @override
   InterfaceType get stringType =>  stringClass.computeType(compiler);
+
+  @override
+  InterfaceType iterableType([DartType elementType = const DynamicType()]) {
+    return iterableClass.computeType(compiler)
+        .createInstantiation([elementType]);
+  }
+
+  @override
+  InterfaceType futureType([DartType elementType = const DynamicType()]) {
+    return futureClass.computeType(compiler).createInstantiation([elementType]);
+  }
+
+  @override
+  InterfaceType streamType([DartType elementType = const DynamicType()]) {
+    return streamClass.computeType(compiler).createInstantiation([elementType]);
+  }
 }
 
 typedef void InternalErrorFunction(Spannable location, String message);
diff --git a/pkg/compiler/lib/src/core_types.dart b/pkg/compiler/lib/src/core_types.dart
index 291978d..ba71b3f 100644
--- a/pkg/compiler/lib/src/core_types.dart
+++ b/pkg/compiler/lib/src/core_types.dart
@@ -40,4 +40,16 @@
   /// [keyType] and [valueType] as its type arguments.
   InterfaceType mapType([DartType keyType = const DynamicType(),
                          DartType valueType = const DynamicType()]);
+
+  /// Returns an instance of the `Iterable` type defined in 'dart:core' with
+  /// [elementType] as its type argument.
+  InterfaceType iterableType([DartType elementType = const DynamicType()]);
+
+  /// Returns an instance of the `Future` type defined in 'dart:async' with
+  /// [elementType] as its type argument.
+  InterfaceType futureType([DartType elementType = const DynamicType()]);
+
+  /// Returns an instance of the `Stream` type defined in 'dart:async' with
+  /// [elementType] as its type argument.
+  InterfaceType streamType([DartType elementType = const DynamicType()]);
 }
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index cbf4ef5..335a92b 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -14,6 +14,7 @@
 import '../util/util.dart';
 import 'cps_ir_nodes.dart';
 import '../types/types.dart' show TypeMask, TypesTask;
+import '../core_types.dart' show CoreTypes;
 import '../types/constants.dart' show computeTypeMask;
 import '../elements/elements.dart' show ClassElement, Element, Entity,
     FieldElement, FunctionElement, ParameterElement;
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index c90f777..dc36d80 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -53,6 +53,7 @@
   TypeMask get listType => inferrer.listType;
   TypeMask get mapType => inferrer.mapType;
 
+  // TODO(karlklose): remove compiler here.
   TypeMaskSystem(dart2js.Compiler compiler)
     : inferrer = compiler.typesTask,
       classWorld = compiler.world;
@@ -92,8 +93,6 @@
  * by Wegman, Zadeck.
  */
 class TypePropagator<T> extends PassMixin {
-  // TODO(karlklose): remove reference to _compiler. It is currently used to
-  // compute [TypeMask]s.
   final types.DartTypes _dartTypes;
 
   // The constant system is used for evaluation of expressions with constant
@@ -103,7 +102,6 @@
   final dart2js.InternalErrorFunction _internalError;
   final Map<Node, _AbstractValue> _types;
 
-
   TypePropagator(this._dartTypes,
                  this._constantSystem,
                  this._typeSystem,
@@ -307,42 +305,43 @@
   final Set<Definition> defWorkset = new Set<Definition>();
 
   final dart2js.ConstantSystem constantSystem;
-  final TypeSystem typeSystem;
+  final TypeSystem<T> typeSystem;
   final dart2js.InternalErrorFunction internalError;
   final types.DartTypes _dartTypes;
 
-  _AbstractValue unknownDynamic;
+  _AbstractValue<T> unknownDynamic;
 
-  _AbstractValue unknown([T t]) {
+  _AbstractValue<T> unknown([T t]) {
     if (t == null) {
       return unknownDynamic;
     } else {
-      return new _AbstractValue.unknown(t);
+      return new _AbstractValue<T>.unknown(t);
     }
   }
 
-  _AbstractValue nonConst([T type]) {
+  _AbstractValue<T> nonConst([T type]) {
     if (type == null) {
       type = typeSystem.dynamicType;
     }
-    return new _AbstractValue.nonConst(type);
+    return new _AbstractValue<T>.nonConst(type);
   }
 
-  _AbstractValue constantValue(ConstantValue constant, T type) {
-    return new _AbstractValue(constant, type);
+  _AbstractValue<T> constantValue(ConstantValue constant, T type) {
+    return new _AbstractValue<T>(constant, type);
   }
 
   // Stores the current lattice value for nodes. Note that it contains not only
   // definitions as keys, but also expressions such as method invokes.
   // Access through [getValue] and [setValue].
-  final Map<Node, _AbstractValue> values;
+  final Map<Node, _AbstractValue<T>> values;
 
   _TypePropagationVisitor(this.constantSystem,
                           TypeSystem typeSystem,
                           this.values,
                           this.internalError,
                           this._dartTypes)
-    : this.unknownDynamic = new _AbstractValue.unknown(typeSystem.dynamicType),
+    : this.unknownDynamic =
+          new _AbstractValue<T>.unknown(typeSystem.dynamicType),
       this.typeSystem = typeSystem;
 
   void analyze(ExecutableDefinition root) {
@@ -387,17 +386,17 @@
   /// Returns the lattice value corresponding to [node], defaulting to unknown.
   ///
   /// Never returns null.
-  _AbstractValue getValue(Node node) {
-    _AbstractValue value = values[node];
+  _AbstractValue<T> getValue(Node node) {
+    _AbstractValue<T> value = values[node];
     return (value == null) ? unknown() : value;
   }
 
   /// Joins the passed lattice [updateValue] to the current value of [node],
   /// and adds it to the definition work set if it has changed and [node] is
   /// a definition.
-  void setValue(Node node, _AbstractValue updateValue) {
-    _AbstractValue oldValue = getValue(node);
-    _AbstractValue newValue = updateValue.join(oldValue, typeSystem);
+  void setValue(Node node, _AbstractValue<T> updateValue) {
+    _AbstractValue<T> oldValue = getValue(node);
+    _AbstractValue<T> newValue = updateValue.join(oldValue, typeSystem);
     if (oldValue == newValue) {
       return;
     }
@@ -472,7 +471,7 @@
     // continuation. Note that this is effectively a phi node in SSA terms.
     for (int i = 0; i < node.arguments.length; i++) {
       Definition def = node.arguments[i].definition;
-      _AbstractValue cell = getValue(def);
+      _AbstractValue<T> cell = getValue(def);
       setValue(cont.parameters[i], cell);
     }
   }
@@ -483,13 +482,13 @@
 
     /// Sets the value of both the current node and the target continuation
     /// parameter.
-    void setValues(_AbstractValue updateValue) {
+    void setValues(_AbstractValue<T> updateValue) {
       setValue(node, updateValue);
       Parameter returnValue = cont.parameters[0];
       setValue(returnValue, updateValue);
     }
 
-    _AbstractValue lhs = getValue(node.receiver.definition);
+    _AbstractValue<T> lhs = getValue(node.receiver.definition);
     if (lhs.isUnknown) {
       // This may seem like a missed opportunity for evaluating short-circuiting
       // boolean operations; we are currently skipping these intentionally since
@@ -523,7 +522,7 @@
     } else if (node.selector.argumentCount == 1) {
       // Binary operator.
 
-      _AbstractValue rhs = getValue(node.arguments[0].definition);
+      _AbstractValue<T> rhs = getValue(node.arguments[0].definition);
       if (!rhs.isConstant) {
         setValues(rhs);
         return;
@@ -541,7 +540,7 @@
       setValues(nonConst());
     } else {
       T type = typeSystem.typeOf(result);
-      setValues(new _AbstractValue(result, type));
+      setValues(new _AbstractValue<T>(result, type));
     }
    }
 
@@ -568,7 +567,7 @@
     Continuation cont = node.continuation.definition;
     setReachable(cont);
 
-    void setValues(_AbstractValue updateValue) {
+    void setValues(_AbstractValue<T> updateValue) {
       setValue(node, updateValue);
       Parameter returnValue = cont.parameters[0];
       setValue(returnValue, updateValue);
@@ -595,7 +594,7 @@
       });
       LiteralDartString dartString = new LiteralDartString(allStrings.join());
       ConstantValue constant = new StringConstantValue(dartString);
-      setValues(new _AbstractValue(constant, type));
+      setValues(new _AbstractValue<T>(constant, type));
     } else {
       setValues(nonConst(type));
     }
@@ -603,7 +602,7 @@
 
   void visitBranch(Branch node) {
     IsTrue isTrue = node.condition;
-    _AbstractValue conditionCell = getValue(isTrue.value.definition);
+    _AbstractValue<T> conditionCell = getValue(isTrue.value.definition);
 
     if (conditionCell.isUnknown) {
       return;  // And come back later.
@@ -630,7 +629,7 @@
     Continuation cont = node.continuation.definition;
     setReachable(cont);
 
-    void setValues(_AbstractValue updateValue) {
+    void setValues(_AbstractValue<T> updateValue) {
       setValue(node, updateValue);
       Parameter returnValue = cont.parameters[0];
       setValue(returnValue, updateValue);
@@ -641,7 +640,7 @@
       setValues(nonConst());
     }
 
-    _AbstractValue cell = getValue(node.receiver.definition);
+    _AbstractValue<T> cell = getValue(node.receiver.definition);
     if (cell.isUnknown) {
       return;  // And come back later.
     } else if (cell.isNonConst) {
@@ -655,7 +654,7 @@
       types.DartType constantType = constant.getType(_dartTypes.coreTypes);
 
       T type = typeSystem.boolType;
-      _AbstractValue result;
+      _AbstractValue<T> result;
       if (constant.isNull &&
           checkedType != _dartTypes.coreTypes.nullType &&
           checkedType != _dartTypes.coreTypes.objectType) {
@@ -775,8 +774,8 @@
   // JavaScript specific nodes.
 
   void visitIdentical(Identical node) {
-    _AbstractValue leftConst = getValue(node.left.definition);
-    _AbstractValue rightConst = getValue(node.right.definition);
+    _AbstractValue<T> leftConst = getValue(node.left.definition);
+    _AbstractValue<T> rightConst = getValue(node.right.definition);
     ConstantValue leftValue = leftConst.constant;
     ConstantValue rightValue = rightConst.constant;
     if (leftConst.isUnknown || rightConst.isUnknown) {
@@ -797,7 +796,7 @@
       PrimitiveConstantValue right = rightValue;
       ConstantValue result =
           new BoolConstantValue(left.primitiveValue == right.primitiveValue);
-      setValue(node, new _AbstractValue(result, typeSystem.boolType));
+      setValue(node, new _AbstractValue<T>(result, typeSystem.boolType));
     }
   }
 
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index a055e95..b7c4bba 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -1157,16 +1157,16 @@
 /// Enum for the synchronous/asynchronous function body modifiers.
 class AsyncMarker {
   /// The default function body marker.
-  static AsyncMarker SYNC = const AsyncMarker._();
+  static const AsyncMarker SYNC = const AsyncMarker._();
 
   /// The `sync*` function body marker.
-  static AsyncMarker SYNC_STAR = const AsyncMarker._(isYielding: true);
+  static const AsyncMarker SYNC_STAR = const AsyncMarker._(isYielding: true);
 
   /// The `async` function body marker.
-  static AsyncMarker ASYNC = const AsyncMarker._(isAsync: true);
+  static const AsyncMarker ASYNC = const AsyncMarker._(isAsync: true);
 
   /// The `async*` function body marker.
-  static AsyncMarker ASYNC_STAR =
+  static const AsyncMarker ASYNC_STAR =
       const AsyncMarker._(isAsync: true, isYielding: true);
 
   /// Is `true` if this marker defines the function body to have an
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index edb9c57..b3ec3fd 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -93,6 +93,8 @@
 
   String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old';
 
+  final Annotations annotations = new Annotations();
+
   /// List of [FunctionElement]s that we want to inline always.  This list is
   /// filled when resolution is complete by looking up in [internalLibrary].
   List<FunctionElement> functionsToAlwaysInline;
@@ -459,7 +461,7 @@
     resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
     patchResolverTask = new PatchResolverTask(compiler);
     functionCompiler = USE_CPS_IR
-         ? new CspFunctionCompiler(compiler, this)
+         ? new CpsFunctionCompiler(compiler, this)
          : new SsaFunctionCompiler(this, generateSourceMap);
   }
 
@@ -1805,6 +1807,7 @@
       } else if (uri == DART_HTML) {
         htmlLibraryIsLoaded = true;
       }
+      annotations.onLibraryScanned(library);
     });
   }
 
@@ -2333,6 +2336,65 @@
   }
 }
 
+/// Handling of special annotations for tests.
+class Annotations {
+  static final Uri PACKAGE_EXPECT =
+      new Uri(scheme: 'package', path: 'expect/expect.dart');
+
+  ClassElement expectNoInliningClass;
+  ClassElement expectTrustTypeAnnotationsClass;
+  ClassElement expectAssumeDynamicClass;
+
+  void onLibraryScanned(LibraryElement library) {
+    if (library.canonicalUri == PACKAGE_EXPECT) {
+      expectNoInliningClass = library.find('NoInlining');
+      expectTrustTypeAnnotationsClass = library.find('TrustTypeAnnotations');
+      expectAssumeDynamicClass = library.find('AssumeDynamic');
+      if (expectNoInliningClass == null ||
+          expectTrustTypeAnnotationsClass == null ||
+          expectAssumeDynamicClass == null) {
+        // This is not the package you're looking for.
+        expectNoInliningClass = null;
+        expectTrustTypeAnnotationsClass = null;
+        expectAssumeDynamicClass = null;
+      }
+    }
+  }
+
+  /// Returns `true` if inlining is disabled for [element].
+  bool noInlining(Element element) {
+    return _hasAnnotation(element, expectNoInliningClass);
+  }
+
+  /// Returns `true` if parameter and returns types should be trusted for
+  /// [element].
+  bool trustTypeAnnotations(Element element) {
+    return _hasAnnotation(element, expectTrustTypeAnnotationsClass);
+  }
+
+  /// Returns `true` if inference of parameter types is disabled for [element].
+  bool assumeDynamic(Element element) {
+    return _hasAnnotation(element, expectAssumeDynamicClass);
+  }
+
+  /// Returns `true` if [element] is annotated with [annotationClass].
+  bool _hasAnnotation(Element element, ClassElement annotationClass) {
+    if (annotationClass == null) return false;
+    for (Link<MetadataAnnotation> link = element.metadata;
+         !link.isEmpty;
+         link = link.tail) {
+      ConstantValue value = link.head.constant.value;
+      if (value.isConstructedObject) {
+        ConstructedConstantValue constructedConstant = value;
+        if (constructedConstant.type.element == annotationClass) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+}
+
 class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
   final JavaScriptBackend backend;
 
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index f930b90..1237350 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -83,7 +83,8 @@
     return new js.Fun(parameters, new js.Block(accumulator));
   }
 
-  js.Expression visit(tree_ir.Expression node) {
+  @override
+  js.Expression visitExpression(tree_ir.Expression node) {
     js.Expression result = node.accept(this);
     if (result == null) {
       glue.reportInternalError('$node did not produce code.');
@@ -141,9 +142,9 @@
   @override
   js.Expression visitConditional(tree_ir.Conditional node) {
     return new js.Conditional(
-        visit(node.condition),
-        visit(node.thenExpression),
-        visit(node.elseExpression));
+        visitExpression(node.condition),
+        visitExpression(node.thenExpression),
+        visitExpression(node.elseExpression));
   }
 
   js.Expression buildConstant(ConstantValue constant) {
@@ -166,6 +167,7 @@
     return buildConstant(glue.getConstantForVariable(parameter).value);
   }
 
+  // TODO(karlklose): get rid of the selector argument.
   js.Expression buildStaticInvoke(Selector selector,
                                   Element target,
                                   List<js.Expression> arguments) {
@@ -182,21 +184,31 @@
       return js.propertyCall(interceptorLibrary, selector.name, arguments);
     } else {
       js.Expression elementAccess = glue.staticFunctionAccess(target);
-      List<js.Expression> compiledArguments =
-          selector.makeArgumentsList(target.implementation,
-                                     arguments,
-                                     compileConstant);
-      return new js.Call(elementAccess, compiledArguments);
+      return new js.Call(elementAccess, arguments);
     }
   }
 
+  List<js.Expression> compileStaticArgumentList(
+      Selector selector,
+      Element target, /* TODO(karlklose): this should be the signature. */
+      List<tree_ir.Expression> arguments) {
+    return selector.makeArgumentsList(
+        target.implementation,
+        visitArguments(arguments),
+        compileConstant);
+  }
+
   @override
   js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) {
+    checkStaticTargetIsValid(node, node.target);
+
     if (node.constant != null) return giveup(node);
     registry.registerInstantiatedClass(node.target.enclosingClass);
-    return buildStaticInvoke(node.selector,
-                             node.target,
-                             visitArguments(node.arguments));
+    Selector selector = node.selector;
+    FunctionElement target = node.target;
+    List<js.Expression> arguments =
+        compileStaticArgumentList(selector, target, node.arguments);
+    return buildStaticInvoke(selector, target, arguments);
   }
 
   void registerMethodInvoke(tree_ir.InvokeMethod node) {
@@ -224,14 +236,32 @@
                            visitArguments(node.arguments));
   }
 
+  /// Checks that the target of the static call is not an [ErroneousElement].
+  ///
+  /// This helper should be removed and the code to generate the CPS IR for
+  /// the dart2js backend should construct a call to a helper that throw an
+  /// appropriate error message instead of the static call.
+  ///
+  /// See [SsaBuilder.visitStaticSend] as an example how to do this.
+  void checkStaticTargetIsValid(tree_ir.Node node, Element target) {
+    if (target.isErroneous) {
+      giveup(node, 'cannot generate error handling code'
+                   ' for call to unresolved target');
+    }
+  }
+
   @override
   js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) {
+    checkStaticTargetIsValid(node, node.target);
+
     if (node.target is! FunctionElement) {
       giveup(node, 'static getters and setters are not supported.');
     }
-    return buildStaticInvoke(node.selector,
-                             node.target,
-                             visitArguments(node.arguments));
+    Selector selector = node.selector;
+    FunctionElement target = node.target;
+    List<js.Expression> arguments =
+        compileStaticArgumentList(selector, target, node.arguments);
+    return buildStaticInvoke(selector, target, arguments);
   }
 
   @override
@@ -275,8 +305,9 @@
       entries[2 * i] = visitExpression(node.entries[i].key);
       entries[2 * i + 1] = visitExpression(node.entries[i].value);
     }
-    List<js.Expression> args =
-        <js.Expression>[new js.ArrayInitializer(entries)];
+    List<js.Expression> args = entries.isEmpty
+         ? <js.Expression>[]
+         : <js.Expression>[new js.ArrayInitializer(entries)];
     return buildStaticInvoke(
         new Selector.call(constructor.name, constructor.library, 2),
         constructor,
@@ -285,7 +316,10 @@
 
   @override
   js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
-    return new js.Binary(node.operator, visit(node.left), visit(node.right));
+    return new js.Binary(
+        node.operator,
+        visitExpression(node.left),
+        visitExpression(node.right));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index d50f32a..4797173 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -32,7 +32,7 @@
 import '../../cps_ir/cps_ir_nodes_sexpr.dart';
 import 'js_tree_builder.dart';
 
-class CspFunctionCompiler implements FunctionCompiler {
+class CpsFunctionCompiler implements FunctionCompiler {
   final IrBuilderTask irBuilderTask;
   final ConstantSystem constantSystem;
   final Compiler compiler;
@@ -45,7 +45,7 @@
 
   Tracer get tracer => compiler.tracer;
 
-  CspFunctionCompiler(Compiler compiler, JavaScriptBackend backend)
+  CpsFunctionCompiler(Compiler compiler, JavaScriptBackend backend)
       : irBuilderTask = new IrBuilderTask(compiler),
         fallbackCompiler = new ssa.SsaFunctionCompiler(backend, true),
         constantSystem = backend.constantSystem,
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
index 30d81ed..6e37f27 100644
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
@@ -6,6 +6,7 @@
 
 import '../../dart2jslib.dart' show Compiler;
 import '../../dart_types.dart' show DartType;
+import '../../elements/elements.dart' show ClassElement;
 import '../../js/js.dart' as js;
 import '../../js_backend/js_backend.dart' show
     JavaScriptBackend,
@@ -32,6 +33,7 @@
 import '../model.dart';
 
 
+
 class ModelEmitter {
   final Compiler compiler;
   final Namer namer;
@@ -209,8 +211,7 @@
                                   program.typeToInterceptorMap));
     }
 
-    globals.add(new js.Property(js.string(MANGLED_GLOBAL_NAMES),
-                                js.js('Object.create(null)', [])));
+    globals.add(emitMangledGlobalNames());
 
     globals.add(emitGetTypeFromName());
 
@@ -234,6 +235,24 @@
     return new js.Block(statements);
   }
 
+  js.Property emitMangledGlobalNames() {
+    List<js.Property> names = <js.Property>[];
+
+    // We want to keep the original names for the most common core classes when
+    // calling toString on them.
+    List<ClassElement> nativeClassesNeedingUnmangledName =
+        [compiler.intClass, compiler.doubleClass, compiler.numClass,
+         compiler.stringClass, compiler.boolClass, compiler.nullClass,
+         compiler.listClass];
+    nativeClassesNeedingUnmangledName.forEach((element) {
+        names.add(new js.Property(js.string(namer.getNameOfClass(element)),
+                                  js.string(element.name)));
+    });
+
+    return new js.Property(js.string(MANGLED_GLOBAL_NAMES),
+                           new js.ObjectInitializer(names));
+  }
+
   List<js.Property> emitLoadUrisAndHashes(Map<String, List<Fragment>> loadMap) {
     js.ArrayInitializer outputUris(List<Fragment> fragments) {
       return js.stringArray(fragments.map((DeferredFragment fragment) =>
@@ -428,7 +447,7 @@
     }
     js.Expression fieldName = js.string(field.name);
     js.Expression code = js.js(setterTemplateFor(field.setterFlags), fieldName);
-    String setterName = "${namer.setterPrefix}${field.name}";
+    String setterName = "${namer.setterPrefix}${field.accessorName}";
     return new StubMethod(setterName, code);
   }
 
@@ -785,7 +804,7 @@
     if (typeof descriptor[2] !== 'function') {
       constructor = compileMixinConstructor(name, prototype, descriptor);
       for (var i = 4; i < descriptor.length; i += 2) {
-        parseFunctionDescriptor(prototype, descriptor, descriptor[i + 1]);
+        parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]);
       }
     } else {
       constructor = descriptor[2];
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 206a035..af2b302 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -2478,10 +2478,15 @@
     LocalFunctionElementX function = new LocalFunctionElementX(
         name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
         enclosingElement);
-    function.functionSignatureCache =
-        SignatureResolver.analyze(compiler, node.parameters, node.returnType,
-            function, registry, createRealParameters: true);
     ResolverTask.processAsyncMarker(compiler, function);
+    function.functionSignatureCache = SignatureResolver.analyze(
+        compiler,
+        node.parameters,
+        node.returnType,
+        function,
+        registry,
+        createRealParameters: true,
+        isFunctionExpression: !inFunctionDeclaration);
     checkLocalDefinitionName(node, function);
     registry.defineFunction(node, function);
     if (doAddToScope) {
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 530be43..948a0cb 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -261,13 +261,16 @@
    * real parameters implementing the [ParameterElement] interface. Otherwise,
    * the parameters will only implement [FormalElement].
    */
-  static FunctionSignature analyze(Compiler compiler,
-                                   NodeList formalParameters,
-                                   Node returnNode,
-                                   FunctionTypedElement element,
-                                   ResolutionRegistry registry,
-                                   {MessageKind defaultValuesError,
-                                    bool createRealParameters: false}) {
+  static FunctionSignature analyze(
+      Compiler compiler,
+      NodeList formalParameters,
+      Node returnNode,
+      FunctionTypedElement element,
+      ResolutionRegistry registry,
+      {MessageKind defaultValuesError,
+       bool createRealParameters: false,
+       bool isFunctionExpression: false}) {
+
     SignatureResolver visitor = new SignatureResolver(compiler, element,
         registry, defaultValuesError: defaultValuesError,
         createRealParameters: createRealParameters);
@@ -308,7 +311,27 @@
         registry.registerIsCheck(returnType);
       }
     } else {
-      returnType = visitor.resolveReturnType(returnNode);
+      AsyncMarker asyncMarker = AsyncMarker.SYNC;
+      if (isFunctionExpression) {
+        // Use async marker to determine the return type of function
+        // expressions.
+        FunctionElement function = element;
+        asyncMarker = function.asyncMarker;
+      }
+      switch (asyncMarker) {
+      case AsyncMarker.SYNC:
+        returnType = visitor.resolveReturnType(returnNode);
+        break;
+      case AsyncMarker.SYNC_STAR:
+        returnType = compiler.coreTypes.iterableType();
+        break;
+      case AsyncMarker.ASYNC:
+        returnType = compiler.coreTypes.futureType();
+        break;
+      case AsyncMarker.ASYNC_STAR:
+        returnType = compiler.coreTypes.streamType();
+        break;
+      }
     }
 
     if (element.isSetter && (requiredParameterCount != 1 ||
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 1921450..a688778 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -6,7 +6,6 @@
 
 import '../constants/expressions.dart';
 import '../constants/values.dart' as values;
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
 import '../dart_types.dart' show DartType, GenericType;
 import '../elements/elements.dart';
 import '../universe/universe.dart';
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index f338269..6bec813 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -1629,15 +1629,20 @@
     DartType resultType = analyze(node.expression);
     if (!node.hasStar) {
       if (currentAsyncMarker.isAsync) {
-        resultType =
-            compiler.streamClass.thisType.createInstantiation(
-                <DartType>[resultType]);
+        resultType = compiler.coreTypes.streamType(resultType);
       } else {
-        resultType =
-            compiler.iterableClass.thisType.createInstantiation(
-                 <DartType>[resultType]);
+        resultType = compiler.coreTypes.iterableType(resultType);
+      }
+    } else {
+      if (currentAsyncMarker.isAsync) {
+        // The static type of expression must be assignable to Stream.
+        checkAssignable(node, resultType, compiler.coreTypes.streamType());
+      } else {
+        // The static type of expression must be assignable to Iterable.
+        checkAssignable(node, resultType, compiler.coreTypes.iterableType());
       }
     }
+    // The static type of the result must be assignable to the declared type.
     checkAssignable(node, resultType, expectedReturnType);
     return const StatementType();
   }
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 4945189..909b000 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -176,6 +176,9 @@
 
 useJsBackend(js_backend.JavaScriptBackend backend) {
   backend.assembleCode(null);
+  backend.annotations.noInlining(null);
+  backend.annotations.trustTypeAnnotations(null);
+  backend.annotations.assumeDynamic(null);
 }
 
 useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index c788276..e21429c 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -2085,7 +2085,7 @@
       examples: const [
         "main() async * {}",
         "main() sync * {}",
-        "main() async* { yield * 0; }"
+        "main() async* { yield * null; }"
       ]);
 
   static const MessageKind INVALID_SYNC_MODIFIER = const MessageKind(
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index bdec706..ed094dd 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -396,3 +396,24 @@
   String toString() => message;
   String message;
 }
+
+/// Annotation class for testing of dart2js. Use this as metadata on method
+/// declarations to disable inlining of the annotated method.
+class NoInlining {
+  const NoInlining();
+}
+
+/// Annotation class for testing of dart2js. Use this as metadata on method
+/// declarations to make the type inferrer trust the parameter and return types,
+/// effectively asserting the runtime values will (at least) be subtypes of the
+/// annotated types.
+class TrustTypeAnnotations {
+  const TrustTypeAnnotations();
+}
+
+/// Annotation class for testing of dart2js. Use this as metadata on method
+/// declarations to disable closed world assumptions on parameters, effectively
+/// assuming that the runtime arguments could be any value.
+class AssumeDynamic {
+  const AssumeDynamic();
+}
\ No newline at end of file
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index 542602f..52f2539 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -4,7 +4,9 @@
 
 #include "bin/dartutils.h"
 #include "bin/eventhandler.h"
+#include "bin/lockers.h"
 #include "bin/socket.h"
+#include "bin/thread.h"
 
 #include "include/dart_api.h"
 
@@ -12,8 +14,6 @@
 namespace dart {
 namespace bin {
 
-static const intptr_t kTimerId = -1;
-static const intptr_t kInvalidId = -2;
 
 void TimeoutQueue::UpdateTimeout(Dart_Port port, int64_t timeout) {
   // Find port if present.
@@ -57,19 +57,40 @@
 
 
 static EventHandler* event_handler = NULL;
+static Monitor *shutdown_monitor = NULL;
 
 
 void EventHandler::Start() {
   ASSERT(event_handler == NULL);
+  shutdown_monitor = new Monitor();
   event_handler = new EventHandler();
   event_handler->delegate_.Start(event_handler);
 }
 
 
+void EventHandler::NotifyShutdownDone() {
+  MonitorLocker ml(shutdown_monitor);
+  ml.Notify();
+}
+
+
 void EventHandler::Stop() {
   if (event_handler == NULL) return;
-  event_handler->delegate_.Shutdown();
+
+  // Wait until it has stopped.
+  {
+    MonitorLocker ml(shutdown_monitor);
+
+    // Signal to event handler that we want it to stop.
+    event_handler->delegate_.Shutdown();
+    ml.Wait(Monitor::kNoTimeout);
+  }
+
+  // Cleanup
+  delete event_handler;
   event_handler = NULL;
+  delete shutdown_monitor;
+  shutdown_monitor = NULL;
 }
 
 
@@ -85,7 +106,7 @@
  */
 void FUNCTION_NAME(EventHandler_SendData)(Dart_NativeArguments args) {
   Dart_Handle sender = Dart_GetNativeArgument(args, 0);
-  intptr_t id = kInvalidId;
+  intptr_t id;
   if (Dart_IsNull(sender)) {
     id = kTimerId;
   } else {
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 80efaca..70636bf 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -25,6 +25,7 @@
   kShutdownReadCommand = 9,
   kShutdownWriteCommand = 10,
   kReturnTokenCommand = 11,
+  kSetEventMaskCommand = 12,
   kListeningSocket = 16,
   kPipe = 17,
 };
@@ -32,10 +33,19 @@
 #define COMMAND_MASK ((1 << kCloseCommand) | \
                       (1 << kShutdownReadCommand) | \
                       (1 << kShutdownWriteCommand) | \
-                      (1 << kReturnTokenCommand))
+                      (1 << kReturnTokenCommand) | \
+                      (1 << kSetEventMaskCommand))
+#define EVENT_MASK ((1 << kInEvent) | \
+                    (1 << kOutEvent) | \
+                    (1 << kErrorEvent) | \
+                    (1 << kCloseEvent) | \
+                    (1 << kDestroyedEvent))
 #define IS_COMMAND(data, command_bit) \
     ((data & COMMAND_MASK) == (1 << command_bit))  // NOLINT
-#define ASSERT_NO_COMMAND(data) ASSERT((data & COMMAND_MASK) == 0)  // NOLINT
+#define IS_EVENT(data, event_bit) \
+    ((data & EVENT_MASK) == (1 << event_bit))  // NOLINT
+#define IS_LISTENING_SOCKET(data) \
+    ((data & (1 << kListeningSocket)) != 0)  // NOLINT
 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1))
 
 class TimeoutQueue {
@@ -94,6 +104,78 @@
   Timeout* timeouts_;
 };
 
+
+class InterruptMessage {
+ public:
+  intptr_t id;
+  Dart_Port dart_port;
+  int64_t data;
+};
+
+
+static const int kInterruptMessageSize = sizeof(InterruptMessage);
+static const int kInfinityTimeout = -1;
+static const int kTimerId = -1;
+static const int kShutdownId = -2;
+
+
+template<typename T>
+class CircularLinkedList {
+ public:
+  CircularLinkedList() : head_(NULL) {}
+
+  // Returns true if the list was empty.
+  bool Add(T t) {
+    Entry* e = new Entry(t);
+    if (head_ == NULL) {
+      // Empty list, make e head, and point to itself.
+      e->next_ = e;
+      e->prev_ = e;
+      head_ = e;
+      return true;
+    } else {
+      // Insert e as the last element in the list.
+      e->prev_ = head_->prev_;
+      e->next_ = head_;
+      e->prev_->next_ = e;
+      head_->prev_ = e;
+      return false;
+    }
+  }
+
+  void RemoveHead() {
+    Entry* e = head_;
+    if (e->next_ == e) {
+      head_ = NULL;
+    } else {
+      e->prev_->next_ = e->next_;
+      e->next_->prev_ = e->prev_;
+      head_ = e->next_;
+    }
+    delete e;
+  }
+
+  T head() const { return head_->t; }
+
+  bool HasHead() {
+    return head_ != NULL;
+  }
+
+  void Rotate() {
+    head_ = head_->next_;
+  }
+
+ private:
+  struct Entry {
+    explicit Entry(const T& t) : t(t) {}
+    const T t;
+    Entry* next_;
+    Entry* prev_;
+  };
+
+  Entry* head_;
+};
+
 }  // namespace bin
 }  // namespace dart
 
@@ -120,6 +202,11 @@
   }
 
   /**
+   * Signal to main thread that event handler is done.
+   */
+  void NotifyShutdownDone();
+
+  /**
    * Start the event-handler.
    */
   static void Start();
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 680bcae..204bf8a 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -34,11 +34,6 @@
 namespace dart {
 namespace bin {
 
-static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kInfinityTimeout = -1;
-static const int kTimerId = -1;
-static const int kShutdownId = -2;
-
 
 intptr_t SocketData::GetPollEvents() {
   // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are
@@ -118,12 +113,14 @@
 
 
 EventHandlerImplementation::~EventHandlerImplementation() {
+  VOID_TEMP_FAILURE_RETRY(close(epoll_fd_));
   VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
   VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
 }
 
 
-SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) {
+SocketData* EventHandlerImplementation::GetSocketData(
+    intptr_t fd, bool listening_socket) {
   ASSERT(fd >= 0);
   HashMap::Entry* entry = socket_map_.Lookup(
       GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true);
@@ -132,7 +129,7 @@
   if (sd == NULL) {
     // If there is no data in the hash map for this file descriptor a
     // new SocketData for the file descriptor is inserted.
-    sd = new SocketData(fd);
+    sd = new SocketData(fd, listening_socket);
     entry->value = sd;
   }
   ASSERT(fd == sd->fd());
@@ -173,8 +170,10 @@
     } else if (msg[i].id == kShutdownId) {
       shutdown_ = true;
     } else {
-      SocketData* sd = GetSocketData(msg[i].id);
+      ASSERT((msg[i].data & COMMAND_MASK) != 0);
 
+      SocketData* sd = GetSocketData(
+          msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
       if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
         // Close the socket for reading.
         shutdown(sd->fd(), SHUT_RD);
@@ -198,11 +197,16 @@
             AddToEpollInstance(epoll_fd_, sd);
           }
         }
-      } else {
-        ASSERT_NO_COMMAND(msg[i].data);
+      } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+        // `events` can only have kInEvent/kOutEvent flags set.
+        intptr_t events = msg[i].data & EVENT_MASK;
+        ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
         // Setup events to wait for.
-        sd->SetPortAndMask(msg[i].dart_port, msg[i].data);
+        sd->SetPortAndMask(msg[i].dart_port, events);
         AddToEpollInstance(epoll_fd_, sd);
+      } else {
+        UNREACHABLE();
       }
     }
   }
@@ -299,25 +303,27 @@
   ThreadSignalBlocker signal_blocker(SIGPROF);
   static const intptr_t kMaxEvents = 16;
   struct epoll_event events[kMaxEvents];
-  EventHandlerImplementation* handler =
-      reinterpret_cast<EventHandlerImplementation*>(args);
-  ASSERT(handler != NULL);
-  while (!handler->shutdown_) {
-    int64_t millis = handler->GetTimeout();
+  EventHandler* handler = reinterpret_cast<EventHandler*>(args);
+  EventHandlerImplementation* handler_impl = &handler->delegate_;
+  ASSERT(handler_impl != NULL);
+
+  while (!handler_impl->shutdown_) {
+    int64_t millis = handler_impl->GetTimeout();
     ASSERT(millis == kInfinityTimeout || millis >= 0);
     if (millis > kMaxInt32) millis = kMaxInt32;
     intptr_t result = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(
-        epoll_wait(handler->epoll_fd_, events, kMaxEvents, millis));
+        epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, millis));
     ASSERT(EAGAIN == EWOULDBLOCK);
     if (result == -1) {
       if (errno != EWOULDBLOCK) {
         perror("Poll failed");
       }
     } else {
-      handler->HandleTimeout();
-      handler->HandleEvents(events, result);
+      handler_impl->HandleTimeout();
+      handler_impl->HandleEvents(events, result);
     }
   }
+  handler->NotifyShutdownDone();
 }
 
 
diff --git a/runtime/bin/eventhandler_android.h b/runtime/bin/eventhandler_android.h
index 2eee0af..2f9ab91 100644
--- a/runtime/bin/eventhandler_android.h
+++ b/runtime/bin/eventhandler_android.h
@@ -22,18 +22,11 @@
 namespace dart {
 namespace bin {
 
-class InterruptMessage {
- public:
-  intptr_t id;
-  Dart_Port dart_port;
-  int64_t data;
-};
-
-
 class SocketData {
  public:
-  explicit SocketData(intptr_t fd)
-      : fd_(fd), port_(0), mask_(0), tokens_(16) {
+  explicit SocketData(intptr_t fd, bool listening_socket)
+      : fd_(fd), port_(0), mask_(0), tokens_(16),
+        listening_socket_(listening_socket) {
     ASSERT(fd_ != -1);
   }
 
@@ -55,7 +48,7 @@
   intptr_t fd() { return fd_; }
   Dart_Port port() { return port_; }
 
-  bool IsListeningSocket() { return (mask_ & (1 << kListeningSocket)) != 0; }
+  bool IsListeningSocket() { return listening_socket_; }
 
   // Returns true if the last token was taken.
   bool TakeToken() {
@@ -76,6 +69,7 @@
   Dart_Port port_;
   intptr_t mask_;
   int tokens_;
+  bool listening_socket_;
 };
 
 
@@ -86,7 +80,7 @@
 
   // Gets the socket data structure for a given file
   // descriptor. Creates a new one if one is not found.
-  SocketData* GetSocketData(intptr_t fd);
+  SocketData* GetSocketData(intptr_t fd, bool is_listening);
   void SendData(intptr_t id, Dart_Port dart_port, intptr_t data);
   void Start(EventHandler* handler);
   void Shutdown();
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 97b305b..475b39d 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -28,10 +28,6 @@
 namespace dart {
 namespace bin {
 
-static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kTimerId = -1;
-static const int kShutdownId = -2;
-
 
 intptr_t SocketData::GetPollEvents() {
   // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are
@@ -197,8 +193,10 @@
     } else if (msg[i].id == kShutdownId) {
       shutdown_ = true;
     } else {
+      ASSERT((msg[i].data & COMMAND_MASK) != 0);
+
       SocketData* sd = GetSocketData(
-          msg[i].id, (msg[i].data & (1 << kListeningSocket)) != 0);
+          msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
       if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
         ASSERT(!sd->IsListeningSocket());
         // Close the socket for reading.
@@ -223,13 +221,18 @@
         if (sd->ReturnToken(msg[i].dart_port, count)) {
           AddToEpollInstance(epoll_fd_, sd);
         }
-      } else {
-        ASSERT_NO_COMMAND(msg[i].data);
+      } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+        // `events` can only have kInEvent/kOutEvent flags set.
+        intptr_t events = msg[i].data & EVENT_MASK;
+        ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
         // Setup events to wait for.
         if (sd->AddPort(msg[i].dart_port)) {
-          sd->SetMask(msg[i].data);
+          sd->SetMask(events);
           AddToEpollInstance(epoll_fd_, sd);
         }
+      } else {
+        UNREACHABLE();
       }
     }
   }
@@ -315,6 +318,7 @@
   EventHandler* handler = reinterpret_cast<EventHandler*>(args);
   EventHandlerImplementation* handler_impl = &handler->delegate_;
   ASSERT(handler_impl != NULL);
+
   while (!handler_impl->shutdown_) {
     intptr_t result = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(
         epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, -1));
@@ -327,13 +331,13 @@
       handler_impl->HandleEvents(events, result);
     }
   }
-  delete handler;
+  handler->NotifyShutdownDone();
 }
 
 
 void EventHandlerImplementation::Start(EventHandler* handler) {
   int result = Thread::Start(&EventHandlerImplementation::Poll,
-                                   reinterpret_cast<uword>(handler));
+                             reinterpret_cast<uword>(handler));
   if (result != 0) {
     FATAL1("Failed to start event handler thread %d", result);
   }
diff --git a/runtime/bin/eventhandler_linux.h b/runtime/bin/eventhandler_linux.h
index 0db4f3f..0c5bd26 100644
--- a/runtime/bin/eventhandler_linux.h
+++ b/runtime/bin/eventhandler_linux.h
@@ -21,71 +21,6 @@
 namespace dart {
 namespace bin {
 
-class InterruptMessage {
- public:
-  intptr_t id;
-  Dart_Port dart_port;
-  int64_t data;
-};
-
-template<typename T>
-class CircularLinkedList {
- public:
-  CircularLinkedList() : head_(NULL) {}
-
-  // Returns true if the list was empty.
-  bool Add(T t) {
-    Entry* e = new Entry(t);
-    if (head_ == NULL) {
-      // Empty list, make e head, and point to itself.
-      e->next_ = e;
-      e->prev_ = e;
-      head_ = e;
-      return true;
-    } else {
-      // Insert e as the last element in the list.
-      e->prev_ = head_->prev_;
-      e->next_ = head_;
-      e->prev_->next_ = e;
-      head_->prev_ = e;
-      return false;
-    }
-  }
-
-  void RemoveHead() {
-    Entry* e = head_;
-    if (e->next_ == e) {
-      head_ = NULL;
-    } else {
-      e->prev_->next_ = e->next_;
-      e->next_->prev_ = e->prev_;
-      head_ = e->next_;
-    }
-    delete e;
-  }
-
-  T head() const { return head_->t; }
-
-  bool HasHead() {
-    return head_ != NULL;
-  }
-
-  void Rotate() {
-    head_ = head_->next_;
-  }
-
- private:
-  struct Entry {
-    explicit Entry(const T& t) : t(t) {}
-    const T t;
-    Entry* next_;
-    Entry* prev_;
-  };
-
-  Entry* head_;
-};
-
-
 class ListeningSocketData;
 class SocketData {
  public:
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 49ec247..911cbad 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -27,12 +27,6 @@
 namespace dart {
 namespace bin {
 
-static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kInfinityTimeout = -1;
-static const int kTimerId = -1;
-static const int kShutdownId = -2;
-
-
 bool SocketData::HasReadEvent() {
   return (mask_ & (1 << kInEvent)) != 0;
 }
@@ -142,7 +136,8 @@
 }
 
 
-SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) {
+SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd,
+                                                      bool is_listening) {
   ASSERT(fd >= 0);
   HashMap::Entry* entry = socket_map_.Lookup(
       GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true);
@@ -151,7 +146,7 @@
   if (sd == NULL) {
     // If there is no data in the hash map for this file descriptor a
     // new SocketData for the file descriptor is inserted.
-    sd = new SocketData(fd);
+    sd = new SocketData(fd, is_listening);
     entry->value = sd;
   }
   ASSERT(fd == sd->fd());
@@ -191,7 +186,10 @@
     } else if (msg[i].id == kShutdownId) {
       shutdown_ = true;
     } else {
-      SocketData* sd = GetSocketData(msg[i].id);
+      ASSERT((msg[i].data & COMMAND_MASK) != 0);
+
+      SocketData* sd = GetSocketData(
+          msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
       if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
         // Close the socket for reading.
         shutdown(sd->fd(), SHUT_RD);
@@ -213,14 +211,17 @@
             AddToKqueue(kqueue_fd_, sd);
           }
         }
-      } else {
-        ASSERT_NO_COMMAND(msg[i].data);
+      } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+        // `events` can only have kInEvent/kOutEvent flags set.
+        intptr_t events = msg[i].data & EVENT_MASK;
+        ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
         // Setup events to wait for.
-        ASSERT((msg[i].data > 0) && (msg[i].data < kIntptrMax));
         ASSERT(sd->port() == 0);
-        sd->SetPortAndMask(msg[i].dart_port,
-                           static_cast<intptr_t>(msg[i].data));
+        sd->SetPortAndMask(msg[i].dart_port, events);
         AddToKqueue(kqueue_fd_, sd);
+      } else {
+        UNREACHABLE();
       }
     }
   }
@@ -358,6 +359,7 @@
   EventHandler* handler = reinterpret_cast<EventHandler*>(args);
   EventHandlerImplementation* handler_impl = &handler->delegate_;
   ASSERT(handler_impl != NULL);
+
   while (!handler_impl->shutdown_) {
     int64_t millis = handler_impl->GetTimeout();
     ASSERT(millis == kInfinityTimeout || millis >= 0);
@@ -387,14 +389,14 @@
       handler_impl->HandleEvents(events, result);
     }
   }
-  delete handler;
+  handler->NotifyShutdownDone();
 }
 
 
 void EventHandlerImplementation::Start(EventHandler* handler) {
   int result =
       Thread::Start(&EventHandlerImplementation::EventHandlerEntry,
-                          reinterpret_cast<uword>(handler));
+                    reinterpret_cast<uword>(handler));
   if (result != 0) {
     FATAL1("Failed to start event handler thread %d", result);
   }
diff --git a/runtime/bin/eventhandler_macos.h b/runtime/bin/eventhandler_macos.h
index 4e32dc0..ebfe251 100644
--- a/runtime/bin/eventhandler_macos.h
+++ b/runtime/bin/eventhandler_macos.h
@@ -21,29 +21,22 @@
 namespace dart {
 namespace bin {
 
-class InterruptMessage {
- public:
-  intptr_t id;
-  Dart_Port dart_port;
-  int64_t data;
-};
-
-
 class SocketData {
  public:
-  explicit SocketData(intptr_t fd)
+  explicit SocketData(intptr_t fd, bool is_listening)
       : fd_(fd),
         port_(0),
         mask_(0),
         tracked_by_kqueue_(false),
-        tokens_(16) {
+        tokens_(16),
+        is_listening_(is_listening) {
     ASSERT(fd_ != -1);
   }
 
   bool HasReadEvent();
   bool HasWriteEvent();
 
-  bool IsListeningSocket() { return (mask_ & (1 << kListeningSocket)) != 0; }
+  bool IsListeningSocket() { return is_listening_; }
 
   void SetPortAndMask(Dart_Port port, intptr_t mask) {
     ASSERT(fd_ != -1);
@@ -77,6 +70,7 @@
   intptr_t mask_;
   bool tracked_by_kqueue_;
   int tokens_;
+  bool is_listening_;
 };
 
 
@@ -87,7 +81,7 @@
 
   // Gets the socket data structure for a given file
   // descriptor. Creates a new one if one is not found.
-  SocketData* GetSocketData(intptr_t fd);
+  SocketData* GetSocketData(intptr_t fd, bool is_listening);
   void SendData(intptr_t id, Dart_Port dart_port, int64_t data);
   void Start(EventHandler* handler);
   void Shutdown();
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index fff9d87..61b6f44 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -29,10 +29,6 @@
 static const int kBufferSize = 64 * 1024;
 static const int kStdOverlappedBufferSize = 16 * 1024;
 
-static const int kInfinityTimeout = -1;
-static const int kTimeoutId = -1;
-static const int kShutdownId = -2;
-
 OverlappedBuffer* OverlappedBuffer::AllocateBuffer(int buffer_size,
                                                    Operation operation) {
   OverlappedBuffer* buffer =
@@ -1011,89 +1007,109 @@
 
 void EventHandlerImplementation::HandleInterrupt(InterruptMessage* msg) {
   ASSERT(this != NULL);
-  if (msg->id == kTimeoutId) {
+  if (msg->id == kTimerId) {
     // Change of timeout request. Just set the new timeout and port as the
     // completion thread will use the new timeout value for its next wait.
     timeout_queue_.UpdateTimeout(msg->dart_port, msg->data);
   } else if (msg->id == kShutdownId) {
     shutdown_ = true;
   } else {
-    // No tokens to return on Windows.
-    if ((msg->data & (1 << kReturnTokenCommand)) != 0) return;
     Handle* handle = reinterpret_cast<Handle*>(msg->id);
     ASSERT(handle != NULL);
     if (handle->is_listen_socket()) {
       ListenSocket* listen_socket =
           reinterpret_cast<ListenSocket*>(handle);
       listen_socket->EnsureInitialized(this);
-      listen_socket->SetPortAndMask(msg->dart_port, msg->data);
 
       Handle::ScopedLock lock(listen_socket);
 
-      // If incoming connections are requested make sure to post already
-      // accepted connections.
-      if ((msg->data & (1 << kInEvent)) != 0) {
-        if (listen_socket->CanAccept()) {
-          int event_mask = (1 << kInEvent);
-          handle->set_mask(handle->mask() & ~event_mask);
-          DartUtils::PostInt32(handle->port(), event_mask);
+      if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
+        // No tokens to return on Windows.
+      } else if (IS_COMMAND(msg->data, kSetEventMaskCommand)) {
+        // `events` can only have kInEvent/kOutEvent flags set.
+        intptr_t events = msg->data & EVENT_MASK;
+        ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
+        listen_socket->SetPortAndMask(msg->dart_port, msg->data);
+
+        // If incoming connections are requested make sure to post already
+        // accepted connections.
+        if ((events & (1 << kInEvent)) != 0) {
+          if (listen_socket->CanAccept()) {
+            int event_mask = (1 << kInEvent);
+            handle->set_mask(handle->mask() & ~event_mask);
+            DartUtils::PostInt32(handle->port(), event_mask);
+          }
         }
+      } else if (IS_COMMAND(msg->data, kCloseCommand)) {
+        handle->SetPortAndMask(msg->dart_port, msg->data);
+        handle->Close();
+      } else {
+        UNREACHABLE();
       }
     } else {
       handle->EnsureInitialized(this);
 
       Handle::ScopedLock lock(handle);
 
-      // Only set mask if we turned on kInEvent or kOutEvent.
-      if ((msg->data & ((1 << kInEvent) | (1 << kOutEvent))) != 0) {
+      if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
+        // No tokens to return on Windows.
+      } else if (IS_COMMAND(msg->data, kSetEventMaskCommand)) {
+        // `events` can only have kInEvent/kOutEvent flags set.
+        intptr_t events = msg->data & EVENT_MASK;
+        ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
         handle->SetPortAndMask(msg->dart_port, msg->data);
-      }
 
-      // Issue a read.
-      if ((msg->data & (1 << kInEvent)) != 0) {
-        if (handle->is_datagram_socket()) {
-          handle->IssueRecvFrom();
-        } else if (handle->is_client_socket()) {
-          if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
-            handle->IssueRead();
-          }
-        } else {
-          handle->IssueRead();
-        }
-      }
-
-      // If out events (can write events) have been requested, and there
-      // are no pending writes, meaning any writes are already complete,
-      // post an out event immediately.
-      if ((msg->data & (1 << kOutEvent)) != 0) {
-        if (!handle->HasPendingWrite()) {
-          if (handle->is_client_socket()) {
+        // Issue a read.
+        if ((msg->data & (1 << kInEvent)) != 0) {
+          if (handle->is_datagram_socket()) {
+            handle->IssueRecvFrom();
+          } else if (handle->is_client_socket()) {
             if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
-              DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+              handle->IssueRead();
             }
           } else {
-            DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+            handle->IssueRead();
           }
         }
-      }
 
-      if (handle->is_client_socket()) {
+        // If out events (can write events) have been requested, and there
+        // are no pending writes, meaning any writes are already complete,
+        // post an out event immediately.
+        if ((msg->data & (1 << kOutEvent)) != 0) {
+          if (!handle->HasPendingWrite()) {
+            if (handle->is_client_socket()) {
+              if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
+                DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+              }
+            } else {
+              DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+            }
+          }
+        }
+      } else if (IS_COMMAND(msg->data, kShutdownReadCommand)) {
+        ASSERT(handle->is_client_socket());
+
         ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(handle);
         if ((msg->data & (1 << kShutdownReadCommand)) != 0) {
           client_socket->Shutdown(SD_RECEIVE);
         }
+      } else if (IS_COMMAND(msg->data, kShutdownWriteCommand)) {
+        ASSERT(handle->is_client_socket());
 
+        ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(handle);
         if ((msg->data & (1 << kShutdownWriteCommand)) != 0) {
           client_socket->Shutdown(SD_SEND);
         }
+      } else if (IS_COMMAND(msg->data, kCloseCommand)) {
+        handle->SetPortAndMask(msg->dart_port, msg->data);
+        handle->Close();
+      } else {
+        UNREACHABLE();
       }
     }
 
-    if ((msg->data & (1 << kCloseCommand)) != 0) {
-      handle->SetPortAndMask(msg->dart_port, msg->data);
-      handle->Close();
-    }
-
     DeleteIfClosed(handle);
   }
 }
@@ -1295,6 +1311,7 @@
   EventHandler* handler = reinterpret_cast<EventHandler*>(args);
   EventHandlerImplementation* handler_impl = &handler->delegate_;
   ASSERT(handler_impl != NULL);
+
   while (!handler_impl->shutdown_) {
     DWORD bytes;
     ULONG_PTR key;
@@ -1344,13 +1361,13 @@
       handler_impl->HandleIOCompletion(bytes, key, overlapped);
     }
   }
-  delete handler;
+  handler->NotifyShutdownDone();
 }
 
 
 void EventHandlerImplementation::Start(EventHandler* handler) {
   int result = Thread::Start(EventHandlerEntry,
-                                   reinterpret_cast<uword>(handler));
+                             reinterpret_cast<uword>(handler));
   if (result != 0) {
     FATAL1("Failed to start event handler thread %d", result);
   }
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index c54ef07..3a9a1f4 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -29,13 +29,6 @@
 class ListenSocket;
 
 
-struct InterruptMessage {
-  intptr_t id;
-  Dart_Port dart_port;
-  int64_t data;
-};
-
-
 // An OverlappedBuffer encapsulates the OVERLAPPED structure and the
 // associated data buffer. For accept it also contains the pre-created
 // socket for the client.
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 251108d..b2723ca 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -75,6 +75,30 @@
 // being allocated.
 static int vm_service_server_port = -1;
 
+
+// Exit code indicating an API error.
+static const int kApiErrorExitCode = 253;
+// Exit code indicating a compilation error.
+static const int kCompilationErrorExitCode = 254;
+// Exit code indicating an unhandled error that is not a compilation error.
+static const int kErrorExitCode = 255;
+
+static void ErrorExit(int exit_code, const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  Log::VPrintErr(format, arguments);
+  va_end(arguments);
+  fflush(stderr);
+
+  Dart_ExitScope();
+  Dart_ShutdownIsolate();
+
+  Dart_Cleanup();
+
+  exit(exit_code);
+}
+
+
 // The environment provided through the command line using -D options.
 static dart::HashMap* environment = NULL;
 
@@ -540,7 +564,8 @@
 #define CHECK_RESULT(result)                                                   \
   if (Dart_IsError(result)) {                                                  \
     *error = strdup(Dart_GetError(result));                                    \
-    *is_compile_error = Dart_IsCompilationError(result);                       \
+    *exit_code = Dart_IsCompilationError(result) ? kCompilationErrorExitCode : \
+        (Dart_IsApiError(result) ? kApiErrorExitCode : kErrorExitCode);        \
     Dart_ExitScope();                                                          \
     Dart_ShutdownIsolate();                                                    \
     return NULL;                                                               \
@@ -552,7 +577,7 @@
                                                 const char* main,
                                                 const char* package_root,
                                                 char** error,
-                                                bool* is_compile_error) {
+                                                int* exit_code) {
   ASSERT(script_uri != NULL);
   IsolateData* isolate_data = new IsolateData(script_uri, package_root);
   Dart_Isolate isolate = NULL;
@@ -640,7 +665,7 @@
                                           const char* package_root,
                                           void* data, char** error) {
   IsolateData* parent_isolate_data = reinterpret_cast<IsolateData*>(data);
-  bool is_compile_error = false;
+  int exit_code = 0;
   if (script_uri == NULL) {
     if (data == NULL) {
       *error = strdup("Invalid 'callback_data' - Unable to spawn new isolate");
@@ -663,7 +688,7 @@
                                      main,
                                      package_root,
                                      error,
-                                     &is_compile_error);
+                                     &exit_code);
 }
 
 
@@ -765,29 +790,6 @@
   return buffer;
 }
 
-
-// Exit code indicating a compilation error.
-static const int kCompilationErrorExitCode = 254;
-
-// Exit code indicating an unhandled error that is not a compilation error.
-static const int kErrorExitCode = 255;
-
-static void ErrorExit(int exit_code, const char* format, ...) {
-  va_list arguments;
-  va_start(arguments, format);
-  Log::VPrintErr(format, arguments);
-  va_end(arguments);
-  fflush(stderr);
-
-  Dart_ExitScope();
-  Dart_ShutdownIsolate();
-
-  Dart_Cleanup();
-
-  exit(exit_code);
-}
-
-
 static void DartExitOnError(Dart_Handle error) {
   if (!Dart_IsError(error)) {
     return;
@@ -855,15 +857,11 @@
 
 static const char* ServiceRequestHandler(
     const char* name,
-    const char** arguments,
-    intptr_t num_arguments,
-    const char** option_keys,
-    const char** option_values,
-    intptr_t num_options,
+    const char** param_keys,
+    const char** param_values,
+    intptr_t num_params,
     void* user_data) {
   DartScope scope;
-  ASSERT(num_arguments > 0);
-  ASSERT(strncmp(arguments[0], "io", 2) == 0);
   // TODO(ajohnsen): Store the library/function in isolate data or user_data.
   Dart_Handle dart_io_str = Dart_NewStringFromCString("dart:io");
   if (Dart_IsError(dart_io_str)) return ServiceRequestError(dart_io_str);
@@ -874,15 +872,14 @@
   if (Dart_IsError(handler_function_name)) {
     return ServiceRequestError(handler_function_name);
   }
-  Dart_Handle paths = Dart_NewList(num_arguments - 1);
-  for (int i = 0; i < num_arguments - 1; i++) {
-    Dart_ListSetAt(paths, i, Dart_NewStringFromCString(arguments[i + 1]));
-  }
-  Dart_Handle keys = Dart_NewList(num_options);
-  Dart_Handle values = Dart_NewList(num_options);
-  for (int i = 0; i < num_options; i++) {
-    Dart_ListSetAt(keys, i, Dart_NewStringFromCString(option_keys[i]));
-    Dart_ListSetAt(values, i, Dart_NewStringFromCString(option_values[i]));
+  // TODO(johnmccutchan): paths is no longer used.  Update the io
+  // _serviceObjectHandler function to use json rpc.
+  Dart_Handle paths = Dart_NewList(0);
+  Dart_Handle keys = Dart_NewList(num_params);
+  Dart_Handle values = Dart_NewList(num_params);
+  for (int i = 0; i < num_params; i++) {
+    Dart_ListSetAt(keys, i, Dart_NewStringFromCString(param_keys[i]));
+    Dart_ListSetAt(values, i, Dart_NewStringFromCString(param_values[i]));
   }
   Dart_Handle args[] = {paths, keys, values};
   Dart_Handle result = Dart_Invoke(io_lib, handler_function_name, 3, args);
@@ -982,18 +979,18 @@
   // Call CreateIsolateAndSetup which creates an isolate and loads up
   // the specified application script.
   char* error = NULL;
-  bool is_compile_error = false;
+  int exit_code = 0;
   char* isolate_name = BuildIsolateName(script_name, "main");
   Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
                                                      "main",
                                                      commandline_package_root,
                                                      &error,
-                                                     &is_compile_error);
+                                                     &exit_code);
   if (isolate == NULL) {
     Log::PrintErr("%s\n", error);
     free(error);
     delete [] isolate_name;
-    exit(is_compile_error ? kCompilationErrorExitCode : kErrorExitCode);
+    exit((exit_code != 0) ? exit_code : kErrorExitCode);
   }
   delete [] isolate_name;
 
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index c2cc587..3983f24 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -238,8 +238,9 @@
   // The lower bits of RETURN_TOKEN_COMMAND messages contains the number
   // of tokens returned.
   static const int RETURN_TOKEN_COMMAND = 11;
+  static const int SET_EVENT_MASK_COMMAND = 12;
   static const int FIRST_COMMAND = CLOSE_COMMAND;
-  static const int LAST_COMMAND = RETURN_TOKEN_COMMAND;
+  static const int LAST_COMMAND = SET_EVENT_MASK_COMMAND;
 
   // Type flag send to the eventhandler providing additional
   // information on the type of the file descriptor.
@@ -523,7 +524,9 @@
 
   _NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET | TYPE_TCP_SOCKET;
 
-  _NativeSocket.listen() :  typeFlags = TYPE_LISTENING_SOCKET | TYPE_TCP_SOCKET;
+  _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET | TYPE_TCP_SOCKET {
+    isClosedWrite = true;
+  }
 
   _NativeSocket.pipe() : typeFlags = TYPE_PIPE;
 
@@ -805,7 +808,7 @@
     if (write) issueWriteEvent();
     if (!flagsSent && !isClosing) {
       flagsSent = true;
-      int flags = 0;
+      int flags = 1 << SET_EVENT_MASK_COMMAND;
       if (!isClosedRead) flags |= 1 << READ_EVENT;
       if (!isClosedWrite) flags |= 1 << WRITE_EVENT;
       sendToEventHandler(flags);
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 46cff7b..55f36e0 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -32,15 +32,7 @@
       }
       var serial = map['id'];
 
-      // If the map contains 'params' then this is a JsonRPC message.
-      // We are currently in the process of switching the vmservice over to
-      // JsonRPC.
-      if (map['params'] != null) {
-        onMessage(serial, new Message.fromJsonRpc(map['method'],
-                                                  map['params']));
-      } else {
-        onMessage(serial, new Message.fromUri(Uri.parse(map['method'])));
-      }
+      onMessage(serial, new Message.fromJsonRpc(map['method'], map['params']));
     } else {
       socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
     }
@@ -219,4 +211,4 @@
 }
 
 void _notifyServerState(String ip, int port)
-    native "VMServiceIO_NotifyServerState";
\ No newline at end of file
+    native "VMServiceIO_NotifyServerState";
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index f28b53a..f7fbfe3 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2770,29 +2770,21 @@
  * a service request it can't handle and the service request command name
  * matches one of the embedder registered handlers.
  *
- * \param name The service request command name. Always the first entry
- *   in the arguments array. Will match the name the callback was
- *   registered with.
- * \param arguments The service request command arguments. Incoming service
- *   request paths are split like file system paths and flattened into an array
- *   (e.g. /foo/bar becomes the array ["foo", "bar"].
- * \param num_arguments The length of the arguments array.
- * \param option_keys Service requests can have options key-value pairs. The
+ * \param method The rpc method name.
+ * \param param_keys Service requests can have key-value pair parameters. The
  *   keys and values are flattened and stored in arrays.
- * \param option_values The values associated with the keys.
- * \param num_options The length of the option_keys and option_values array.
+ * \param param_values The values associated with the keys.
+ * \param num_params The length of the param_keys and param_values arrays.
  * \param user_data The user_data pointer registered with this handler.
  *
  * \return Returns a C string containing a valid JSON object. The returned
  * pointer will be freed by the VM by calling free.
  */
 typedef const char* (*Dart_ServiceRequestCallback)(
-    const char* name,
-    const char** arguments,
-    intptr_t num_arguments,
-    const char** option_keys,
-    const char** option_values,
-    intptr_t num_options,
+    const char* method,
+    const char** param_keys,
+    const char** param_values,
+    intptr_t num_params,
     void* user_data);
 
 /**
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 71d59b3..a4217b9 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -21,3 +21,54 @@
   static const List<String> _enum_names = null;
   String toString() => _enum_names[index];
 }
+
+typedef bool SyncGeneratorCallback(Iterator iterator);
+
+// _SyncIterable and _syncIterator are used by the compiler to
+// implement sync* generator functions. A sync* generator allocates
+// and returns a new _SyncIterable object.
+class _SyncIterable extends IterableBase {
+  // moveNextFn is the closurized body of the generator function.
+  final SyncGeneratorCallback moveNextFn;
+
+  const _SyncIterable(this.moveNextFn);
+
+  get iterator {
+    return new _SyncIterator(moveNextFn._clone());
+  }
+}
+
+class _SyncIterator implements Iterator {
+  bool isYieldEach;  // Set by generated code for the yield* statement.
+  Iterator yieldEachIterator;
+  var current;  // Set by generated code for the yield and yield* statement.
+  SyncGeneratorCallback moveNextFn;
+
+  _SyncIterator(this.moveNextFn);
+
+  bool moveNext() {
+    if (moveNextFn == null) {
+      return false;
+    }
+    while(true) {
+      if (yieldEachIterator != null) {
+        if (yieldEachIterator.moveNext()) {
+          current = yieldEachIterator.current;
+          return true;
+        }
+        yieldEachIterator = null;
+      }
+      isYieldEach = false;
+      if (!moveNextFn(this)) {
+        moveNextFn = null;
+        current = null;
+        return false;
+      }
+      if (isYieldEach && (current is Iterable)) {
+        yieldEachIterator = current.iterator;
+        continue;
+      }
+      return true;    
+    }
+  }
+}
diff --git a/runtime/lib/function.cc b/runtime/lib/function.cc
index 3f55293..801ad54 100644
--- a/runtime/lib/function.cc
+++ b/runtime/lib/function.cc
@@ -74,4 +74,28 @@
   return Object::null();
 }
 
+
+DEFINE_NATIVE_ENTRY(FunctionImpl_clone, 1) {
+  const Instance& receiver = Instance::CheckedHandle(
+      isolate, arguments->NativeArgAt(0));
+  ASSERT(receiver.IsClosure());
+  if (receiver.IsClosure()) {
+    const Function& func =
+        Function::Handle(isolate, Closure::function(receiver));
+    const Context& ctx =
+        Context::Handle(isolate, Closure::context(receiver));
+    Context& cloned_ctx =
+        Context::Handle(isolate, Context::New(ctx.num_variables()));
+    cloned_ctx.set_parent(Context::Handle(isolate, ctx.parent()));
+    Object& inst = Object::Handle(isolate);
+    for (int i = 0; i < ctx.num_variables(); i++) {
+      inst = ctx.At(i);
+      cloned_ctx.SetAt(i, inst);
+    }
+    return Closure::New(func, cloned_ctx);
+  }
+  return Object::null();
+}
+
+
 }  // namespace dart
diff --git a/runtime/lib/function.dart b/runtime/lib/function.dart
index 8147b2d..d91ce66 100644
--- a/runtime/lib/function.dart
+++ b/runtime/lib/function.dart
@@ -9,4 +9,6 @@
   int get hashCode native "FunctionImpl_hashCode";
 
   _FunctionImpl get call => this;
+
+  _FunctionImpl _clone() native "FunctionImpl_clone";
 }
diff --git a/runtime/observatory/bin/shell.dart b/runtime/observatory/bin/shell.dart
index ef2459c..ae4e7ff 100644
--- a/runtime/observatory/bin/shell.dart
+++ b/runtime/observatory/bin/shell.dart
@@ -11,17 +11,19 @@
 // Simple demo for service_io library. Connects to localhost on the default
 // port, picks the first isolate, reads requests from stdin, and prints
 // results to stdout. Example session:
-// <<< prefix /isolates/1071334835
+// <<< isolate isolates/1071334835
 // >>> /classes/40
 // <<< {"type":"Class","id":"classes\/40","name":"num","user_name":"num",...
 // >>> /objects/0
 // >>> {"type":"Array","class":{"type":"@Class","id":"classes\/62",...
 
-void repl(VM vm, String prefix, String lastResult) {
+void repl(VM vm, Isolate isolate, String lastResult) {
   print(lastResult);
-  // TODO(turnidge): use the non-deprecated api here.
-  vm.getStringDeprecated(prefix + stdin.readLineSync()).then((String result) {
-    repl(vm, prefix, result);
+  Map params = {
+    'objectId': stdin.readLineSync(),
+  };
+  isolate.invokeRpcNoUpgrade('getObject', params).then((Map result) {
+    repl(vm, isolate, result.toString());
   });
 }
 
@@ -29,7 +31,6 @@
   String addr = 'ws://localhost:8181/ws';
   new WebSocketVM(new WebSocketVMTarget(addr)).load().then((VM vm) {
     Isolate isolate = vm.isolates.first;
-    String prefix = '${isolate.link}';
-    repl(vm, prefix, 'prefix $prefix');
+    repl(vm, isolate, 'isolate ${isolate.id}');
   });
 }
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index f63249d..c4eec73 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -2,7 +2,6 @@
 
 // Export elements.
 export 'package:observatory/src/elements/action_link.dart';
-export 'package:observatory/src/elements/breakpoint_list.dart';
 export 'package:observatory/src/elements/class_ref.dart';
 export 'package:observatory/src/elements/class_tree.dart';
 export 'package:observatory/src/elements/class_view.dart';
@@ -21,6 +20,7 @@
 export 'package:observatory/src/elements/flag_list.dart';
 export 'package:observatory/src/elements/function_ref.dart';
 export 'package:observatory/src/elements/function_view.dart';
+export 'package:observatory/src/elements/general_error.dart';
 export 'package:observatory/src/elements/heap_map.dart';
 export 'package:observatory/src/elements/heap_profile.dart';
 export 'package:observatory/src/elements/instance_ref.dart';
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index eeb782d..4cc405c 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -1,5 +1,4 @@
 <link rel="import" href="src/elements/action_link.html">
-<link rel="import" href="src/elements/breakpoint_list.html">
 <link rel="import" href="src/elements/class_ref.html">
 <link rel="import" href="src/elements/class_tree.html">
 <link rel="import" href="src/elements/class_view.html">
@@ -16,6 +15,7 @@
 <link rel="import" href="src/elements/flag_list.html">
 <link rel="import" href="src/elements/function_ref.html">
 <link rel="import" href="src/elements/function_view.html">
+<link rel="import" href="src/elements/general_error.html">
 <link rel="import" href="src/elements/heap_map.html">
 <link rel="import" href="src/elements/io_view.html">
 <link rel="import" href="src/elements/isolate_ref.html">
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index c082fdf..f417b88 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -58,10 +58,7 @@
   final Map params;
   final Completer<String> completer;
 
-   _WebSocketRequest.old(this.method)
-      : params = null, completer = new Completer<String>();
-
-   _WebSocketRequest.rpc(this.method, this.params)
+  _WebSocketRequest(this.method, this.params)
       : completer = new Completer<String>();
 }
 
@@ -128,31 +125,6 @@
     _notifyDisconnect();
   }
 
-  Future<String> getStringDeprecated(String id) {
-    if (!_hasInitiatedConnect) {
-      _hasInitiatedConnect = true;
-      _webSocket.connect(
-          target.networkAddress, _onOpen, _onMessage, _onError, _onClose);
-    }
-    return _makeRequest(id);
-  }
-
-  /// Add a request for [id] to pending requests.
-  Future<String> _makeRequest(String id) {
-    assert(_hasInitiatedConnect);
-    // Create request.
-    String serial = (_requestSerial++).toString();
-    var request = new _WebSocketRequest.old(id);
-    if (_webSocket.isOpen) {
-      // Already connected, send request immediately.
-      _sendRequest(serial, request);
-    } else {
-      // Not connected yet, add to delayed requests.
-      _delayedRequests[serial] = request;
-    }
-    return request.completer.future;
-  }
-
   Future<String> invokeRpcRaw(String method, Map params) {
     if (!_hasInitiatedConnect) {
       _hasInitiatedConnect = true;
@@ -160,7 +132,7 @@
           target.networkAddress, _onOpen, _onMessage, _onError, _onClose);
     }
     String serial = (_requestSerial++).toString();
-    var request = new _WebSocketRequest.rpc(method, params);
+    var request = new _WebSocketRequest(method, params);
     if (_webSocket.isOpen) {
       // Already connected, send request immediately.
       _sendRequest(serial, request);
@@ -289,7 +261,9 @@
   /// Send the request over WebSocket.
   void _sendRequest(String serial, _WebSocketRequest request) {
     assert (_webSocket.isOpen);
-    if (request.method != 'getTagProfile') {
+    if (request.method != 'getTagProfile' &&
+        request.method != 'getIsolateMetric' &&
+        request.method != 'getVMMetric') {
       Logger.root.info('GET ${request.method} from ${target.networkAddress}');
     }
     // Mark request as pending.
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index cee60ba..447e8db 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -103,6 +103,9 @@
   }
 
   void _registerPages() {
+    _pageRegistry.add(new VMPage(this));
+    _pageRegistry.add(new FlagsPage(this));
+    _pageRegistry.add(new InspectPage(this));
     _pageRegistry.add(new ClassTreePage(this));
     _pageRegistry.add(new DebuggerPage(this));
     _pageRegistry.add(new CpuProfilerPage(this));
@@ -111,9 +114,9 @@
     _pageRegistry.add(new VMConnectPage(this));
     _pageRegistry.add(new ErrorViewPage(this));
     _pageRegistry.add(new MetricsPage(this));
-    // Note that ServiceObjectPage must be the last entry in the list as it is
+    // Note that ErrorPage must be the last entry in the list as it is
     // the catch all.
-    _pageRegistry.add(new ServiceObjectPage(this));
+    _pageRegistry.add(new ErrorPage(this));
   }
 
   void _onError(ServiceError error) {
@@ -153,11 +156,12 @@
     if (_traceView != null) {
       _traceView.tracer = Tracer.current;
     }
+    Uri uri = Uri.parse(url);
     for (var i = 0; i < _pageRegistry.length; i++) {
       var page = _pageRegistry[i];
-      if (page.canVisit(url)) {
+      if (page.canVisit(uri)) {
         _installPage(page);
-        page.visit(url, argsMap);
+        page.visit(uri, argsMap);
         return;
       }
     }
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 2942905..c777579 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -26,57 +26,25 @@
     element = null;
   }
 
-  /// Called when the page should update its state based on [url].
+  /// Called when the page should update its state based on [uri].
   /// NOTE: Only called when the page is installed.
-  void visit(String url, Map argsMap) {
+  void visit(Uri uri, Map argsMap) {
     args = toObservable(argsMap);
-    _visit(url);
+    _visit(uri);
   }
 
   // Overridden by subclasses.
-  void _visit(String url);
+  void _visit(Uri uri);
 
-  /// Called to test whether this page can visit [url].
-  bool canVisit(String url);
+  /// Called to test whether this page can visit [uri].
+  bool canVisit(Uri uri);
 }
 
-/// A general service object viewer.
-class ServiceObjectPage extends Page {
-  ServiceObjectPage(app) : super(app);
-
-  void onInstall() {
-    if (element == null) {
-      /// Lazily create page.
-      element = new Element.tag('service-view');
-    }
-  }
-
-  void _visit(String url) {
-    assert(element != null);
-    assert(canVisit(url));
-    if (url == '') {
-      // Nothing requested.
-      return;
-    }
-    /// Request url from VM and display it.
-    app.vm.getDeprecated(url).then((obj) {
-      ServiceObjectViewElement serviceElement = element;
-      serviceElement.object = obj;
-    }).catchError((e) {
-      Logger.root.severe('ServiceObjectPage visit error: $e');
-    });
-  }
-
-  /// Catch all.
-  bool canVisit(String url) => true;
-}
-
-class IsolateSuffixPage extends Page {
-  final String pagePrefix;
+/// A [SimplePage] matches a single uri path and displays a single element.
+class SimplePage extends Page {
+  final String path;
   final String elementTagName;
-  String _isolateId;
-  String get isolateId => _isolateId;
-  IsolateSuffixPage(this.pagePrefix, this.elementTagName, app) : super(app);
+  SimplePage(this.path, this.elementTagName, app) : super(app);
 
   void onInstall() {
     if (element == null) {
@@ -84,30 +52,117 @@
     }
   }
 
-  void _visit(String url) {
-    assert(url != null);
-    assert(canVisit(url));
-    _isolateId = url.substring(pagePrefix.length);
+  void _visit(Uri uri) {
+    assert(uri != null);
+    assert(canVisit(uri));
   }
 
-  Future<Isolate> getIsolate() {
-    return app.vm.getIsolate(isolateId).catchError((e) {
-      Logger.root.severe('$pagePrefix visit error: $e');
+  Future<Isolate> getIsolate(Uri uri) {
+    return app.vm.getIsolate(uri.queryParameters['isolateId']).catchError((e) {
+      Logger.root.severe('$path visit error: $e');
       return e;
     });
   }
 
-  bool canVisit(String url) => url.startsWith(pagePrefix);
+  bool canVisit(Uri uri) => uri.path == path;
+}
+
+/// Error page for unrecognized paths.
+class ErrorPage extends Page {
+  ErrorPage(app) : super(app);
+
+  void onInstall() {
+    if (element == null) {
+      // Lazily create page.
+      element = new Element.tag('general-error');
+    }
+  }
+
+  void _visit(Uri uri) {
+    assert(element != null);
+    assert(canVisit(uri));
+
+    /*
+    if (uri.path == '') {
+      // Nothing requested.
+      return;
+    }
+    */
+
+    if (element != null) {
+      GeneralErrorElement serviceElement = element;
+      serviceElement.message = "Path '${uri.path}' not found";
+    }
+  }
+
+  /// Catch all.
+  bool canVisit(Uri uri) => true;
+}
+
+/// Top-level vm info page.
+class VMPage extends SimplePage {
+  VMPage(app) : super('vm', 'service-view', app);
+
+  void _visit(Uri uri) {
+    super._visit(uri);
+    app.vm.reload().then((vm) {
+      if (element != null) {
+        ServiceObjectViewElement serviceElement = element;
+        serviceElement.object = vm;
+      }
+    }).catchError((e) {
+      Logger.root.severe('VMPage visit error: $e');
+    });
+  }
+}
+
+class FlagsPage extends SimplePage {
+  FlagsPage(app) : super('flags', 'flag-list', app);
+
+  void _visit(Uri uri) {
+    super._visit(uri);
+    app.vm.getFlagList().then((flags) {
+      if (element != null) {
+        FlagListElement serviceElement = element;
+        serviceElement.flagList = flags;
+      }
+    }).catchError((e) {
+      Logger.root.severe('FlagsPage visit error: $e');
+    });
+  }
+}
+
+class InspectPage extends SimplePage {
+  InspectPage(app) : super('inspect', 'service-view', app);
+
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
+      var objectId = uri.queryParameters['objectId'];
+      if (objectId == null) {
+        isolate.reload().then(_visitObject);
+      } else {
+        isolate.getObject(objectId).then(_visitObject);
+      }
+    });
+  }
+
+  void _visitObject(obj) {
+    if (element != null) {
+      ServiceObjectViewElement serviceElement = element;
+      serviceElement.object = obj;
+    }
+  }
 }
 
 
 /// Class tree page.
-class ClassTreePage extends IsolateSuffixPage {
-  ClassTreePage(app) : super('class-tree/', 'class-tree', app);
+class ClassTreePage extends SimplePage {
+  ClassTreePage(app) : super('class-tree', 'class-tree', app);
 
-  void _visit(String url) {
-    super._visit(url);
-    getIsolate().then((isolate) {
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
       if (element != null) {
         /// Update the page.
         ClassTreeElement page = element;
@@ -117,12 +172,12 @@
   }
 }
 
-class DebuggerPage extends IsolateSuffixPage {
-  DebuggerPage(app) : super('debugger/', 'debugger-page', app);
+class DebuggerPage extends SimplePage {
+  DebuggerPage(app) : super('debugger', 'debugger-page', app);
 
-  void _visit(String url) {
-    super._visit(url);
-    getIsolate().then((isolate) {
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
       if (element != null) {
         /// Update the page.
         DebuggerPageElement page = element;
@@ -132,12 +187,12 @@
   }
 }
 
-class CpuProfilerPage extends IsolateSuffixPage {
-  CpuProfilerPage(app) : super('profiler/', 'cpu-profile', app);
+class CpuProfilerPage extends SimplePage {
+  CpuProfilerPage(app) : super('profiler', 'cpu-profile', app);
 
-  void _visit(String url) {
-    super._visit(url);
-    getIsolate().then((isolate) {
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
       if (element != null) {
         /// Update the page.
         CpuProfileElement page = element;
@@ -147,13 +202,13 @@
   }
 }
 
-class AllocationProfilerPage extends IsolateSuffixPage {
+class AllocationProfilerPage extends SimplePage {
   AllocationProfilerPage(app)
-      : super('allocation-profiler/', 'heap-profile', app);
+      : super('allocation-profiler', 'heap-profile', app);
 
-  void _visit(String url) {
-    super._visit(url);
-    getIsolate().then((isolate) {
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
       if (element != null) {
         /// Update the page.
         HeapProfileElement page = element;
@@ -163,12 +218,12 @@
   }
 }
 
-class HeapMapPage extends IsolateSuffixPage {
-  HeapMapPage(app) : super('heap-map/', 'heap-map', app);
+class HeapMapPage extends SimplePage {
+  HeapMapPage(app) : super('heap-map', 'heap-map', app);
 
-  void _visit(String url) {
-    super._visit(url);
-    getIsolate().then((isolate) {
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
       if (element != null) {
         /// Update the page.
         HeapMapElement page = element;
@@ -188,13 +243,14 @@
     }
   }
 
-  void _visit(String url) {
+  void _visit(Uri uri) {
     assert(element != null);
-    assert(canVisit(url));
+    assert(canVisit(uri));
     (element as ServiceObjectViewElement).object = app.lastErrorOrException;
   }
 
-  bool canVisit(String url) => url.startsWith('error/');
+  // TODO(turnidge): How to test this page?
+  bool canVisit(Uri uri) => uri.path.startsWith('error/');
 }
 
 class VMConnectPage extends Page {
@@ -207,18 +263,16 @@
     assert(element != null);
   }
 
-  void _visit(String url) {
+  void _visit(Uri uri) {
     assert(element != null);
-    assert(canVisit(url));
+    assert(canVisit(uri));
   }
 
-  bool canVisit(String url) => url.startsWith('vm-connect/');
+  // TODO(turnidge): Update this to not have the trailing slash.
+  bool canVisit(Uri uri) => uri.path.startsWith('vm-connect/');
 }
 
 class MetricsPage extends Page {
-  static RegExp _matcher = new RegExp(r'isolates/.*/metrics');
-  static RegExp _isolateMatcher = new RegExp(r'isolates/.*/');
-
   // Page state, retained as long as ObservatoryApplication.
   String selectedMetricId;
 
@@ -266,20 +320,13 @@
     throw new FallThroughError();
   }
 
-  String _isolateId(String url) {
-    // Grab isolate prefix.
-    String isolateId = _isolateMatcher.stringMatch(url);
-    // Remove the trailing slash.
-    return isolateId.substring(0, isolateId.length - 1);
-  }
-
-  void _visit(String url) {
+  void _visit(Uri uri) {
     assert(element != null);
-    assert(canVisit(url));
-    app.vm.getIsolate(_isolateId(url)).then((i) {
+    assert(canVisit(uri));
+    app.vm.getIsolate(uri.queryParameters['isolateId']).then((i) {
       (element as MetricsPageElement).isolate = i;
     });
   }
 
-  bool canVisit(String url) => _matcher.hasMatch(url);
+  bool canVisit(Uri uri) => uri.path == 'metrics';
 }
diff --git a/runtime/observatory/lib/src/elements/breakpoint_list.dart b/runtime/observatory/lib/src/elements/breakpoint_list.dart
deleted file mode 100644
index 157e6c5..0000000
--- a/runtime/observatory/lib/src/elements/breakpoint_list.dart
+++ /dev/null
@@ -1,21 +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 breakpoint_list_element;
-
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-
-// TODO(turnidge): Is a breakpoint list associated with a VM or an isolate?
-@CustomTag('breakpoint-list')
-class BreakpointListElement extends ObservatoryElement {
-  @published ServiceMap msg;
-
-  BreakpointListElement.created() : super.created();
-
-  void refresh(var done) {
-    msg.reload().whenComplete(done);
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/breakpoint_list.html b/runtime/observatory/lib/src/elements/breakpoint_list.html
deleted file mode 100644
index ec2cd7d..0000000
--- a/runtime/observatory/lib/src/elements/breakpoint_list.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-
-<polymer-element name="breakpoint-list" extends="observatory-element">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <nav-bar>
-      <top-nav-menu></top-nav-menu>
-      <isolate-nav-menu isolate="{{ msg.isolate }}"></isolate-nav-menu>
-      <nav-menu link="{{ gotoLink(msg.isolate.relativeLink('debug/breakpoints')) }}" anchor="breakpoints" last="{{ true }}"></nav-menu>
-      <nav-refresh callback="{{ refresh }}"></nav-refresh>
-      <nav-control></nav-control>
-    </nav-bar>
-    <template if="{{ msg['breakpoints'].isEmpty }}">
-      <div>
-        <div>No breakpoints</div>
-      </div>
-    </template>
-    <template if="{{ msg['breakpoints'].isNotEmpty }}">
-      <ul class="list-group">
-      <template repeat="{{ bpt in msg['breakpoints'] }}">
-        <li class="list-group-item">
-          {{ bpt }}
-        </li>
-      </template>
-      </ul>
-    </template>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="breakpoint_list.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/code_view.html b/runtime/observatory/lib/src/elements/code_view.html
index bd1396b..56010b4 100644
--- a/runtime/observatory/lib/src/elements/code_view.html
+++ b/runtime/observatory/lib/src/elements/code_view.html
@@ -57,7 +57,7 @@
     <nav-bar>
       <top-nav-menu></top-nav-menu>
       <isolate-nav-menu isolate="{{ code.isolate }}"></isolate-nav-menu>
-      <nav-menu link="{{ code.link }}" anchor="{{ code.name }}" last="{{ true }}"></nav-menu>
+      <nav-menu link="{{ makeLink('/inspect', code) }}" anchor="{{ code.name }}" last="{{ true }}"></nav-menu>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
       <nav-control></nav-control>
     </nav-bar>
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index 90b1518..cc7d0c0 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -11,7 +11,7 @@
     <nav-bar>
       <top-nav-menu></top-nav-menu>
       <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
-      <nav-menu link="{{ '/profiler' + isolate.link }}" anchor="cpu profile" last="{{ true }}"></nav-menu>
+      <nav-menu link="{{ makeLink('/profiler', isolate) }}" anchor="cpu profile" last="{{ true }}"></nav-menu>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
       <nav-control></nav-control>
     </nav-bar>
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 347cba3..6b15957 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -57,7 +57,7 @@
         <top-nav-menu></top-nav-menu>
         <isolate-nav-menu isolate="{{ isolate }}">
 	</isolate-nav-menu>
-        <nav-menu link="{{ '/debugger' + isolate.link) }}" anchor="debugger" last="{{ true }}"></nav-menu>
+        <nav-menu link="{{ makeLink('/debugger', isolate) }}" anchor="debugger" last="{{ true }}"></nav-menu>
 	<nav-control></nav-control>
       </nav-bar>
 
diff --git a/runtime/observatory/lib/src/elements/field_view.html b/runtime/observatory/lib/src/elements/field_view.html
index e73e292..2a9d728 100644
--- a/runtime/observatory/lib/src/elements/field_view.html
+++ b/runtime/observatory/lib/src/elements/field_view.html
@@ -19,7 +19,7 @@
       <template if="{{ field.owner.type == 'Library' }}">
         <library-nav-menu library="{{ field.owner }}"></library-nav-menu>
       </template>
-      <nav-menu link="{{ field.link }}" anchor="{{ field.name }}" last="{{ true }}"></nav-menu>
+      <nav-menu link="{{ makeLink('/inspect', field) }}" anchor="{{ field.name }}" last="{{ true }}"></nav-menu>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
       <nav-control></nav-control>
     </nav-bar>
diff --git a/runtime/observatory/lib/src/elements/flag_list.html b/runtime/observatory/lib/src/elements/flag_list.html
index d1861df..94a2bdb 100644
--- a/runtime/observatory/lib/src/elements/flag_list.html
+++ b/runtime/observatory/lib/src/elements/flag_list.html
@@ -7,7 +7,7 @@
     <link rel="stylesheet" href="css/shared.css">
     <nav-bar>
       <top-nav-menu></top-nav-menu>
-      <nav-menu link="{{ flagList.vm.relativeLink('flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
+      <nav-menu link="{{ makeLink('/flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
       <nav-control></nav-control>
     </nav-bar>
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index 439b6a6..519cad8 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -21,7 +21,7 @@
       <template if="{{ function.owningLibrary != null }}">
         <library-nav-menu library="{{ function.owningLibrary }}"></library-nav-menu>
       </template>
-      <nav-menu link="{{ function.link }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
+      <nav-menu link="{{ makeLink('/inspect', function) }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
       <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
       <nav-control></nav-control>
diff --git a/runtime/observatory/lib/src/elements/general_error.dart b/runtime/observatory/lib/src/elements/general_error.dart
new file mode 100644
index 0000000..d47ec04
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/general_error.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library general_error_element;
+
+import 'observatory_element.dart';
+import 'package:polymer/polymer.dart';
+
+/// Displays an error message
+@CustomTag('general-error')
+class GeneralErrorElement extends ObservatoryElement {
+  @published String message;
+
+  GeneralErrorElement.created() : super.created();
+}
diff --git a/runtime/observatory/lib/src/elements/general_error.html b/runtime/observatory/lib/src/elements/general_error.html
new file mode 100644
index 0000000..ac32b03
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/general_error.html
@@ -0,0 +1,20 @@
+<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="nav_bar.html">
+<link rel="import" href="observatory_element.html">
+
+<polymer-element name="general-error" extends="observatory-element">
+  <template>
+    <link rel="stylesheet" href="css/shared.css">
+    <nav-bar>
+      <top-nav-menu last="{{ true }}"></top-nav-menu>
+      <nav-control></nav-control>
+    </nav-bar>
+    <div class="content-centered">
+      <h1>Error</h1>
+      <br>
+      <div class="well">{{ message }}</div>
+    </div>
+  </template>
+</polymer-element>
+
+<script type="application/dart" src="general_error.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/heap_map.dart b/runtime/observatory/lib/src/elements/heap_map.dart
index 2e36c2d..05ed60a 100644
--- a/runtime/observatory/lib/src/elements/heap_map.dart
+++ b/runtime/observatory/lib/src/elements/heap_map.dart
@@ -96,7 +96,7 @@
   }
 
   void _updateClassList(classList, int freeClassId) {
-    for (var member in classList['members']) {
+    for (var member in classList['classes']) {
       if (member is! Class) {
         // TODO(turnidge): The printing for some of these non-class
         // members is broken.  Fix this:
@@ -160,8 +160,13 @@
 
   void _handleClick(MouseEvent event) {
     var address = _objectAt(event.offset).address.toRadixString(16);
-    app.locationManager.go(app.locationManager.makeLink(
-        "${isolate.relativeLink('address/$address')}"));
+    isolate.getObjectByAddress(address).then((result) {
+      if (result is DartError) {
+        Logger.root.severe(result.message);
+      } else {
+        app.locationManager.go(gotoLink('/inspect', result));
+      }
+    });
   }
 
   void _updateFragmentationData() {
diff --git a/runtime/observatory/lib/src/elements/heap_map.html b/runtime/observatory/lib/src/elements/heap_map.html
index a4296ab..66bd845 100644
--- a/runtime/observatory/lib/src/elements/heap_map.html
+++ b/runtime/observatory/lib/src/elements/heap_map.html
@@ -22,7 +22,7 @@
   <nav-bar pad="{{ false }}">
     <top-nav-menu></top-nav-menu>
     <isolate-nav-menu isolate="{{ fragmentation.isolate }}"></isolate-nav-menu>
-    <nav-menu link="{{ fragmentation.isolate.relativeLink('heapmap') }}" anchor="heap map" last="{{ true }}"></nav-menu>
+    <nav-menu link="{{ makeLink('/heap-map', fragmentation.isolate) }}" anchor="heap map" last="{{ true }}"></nav-menu>
     <nav-refresh callback="{{ refresh }}"></nav-refresh>
     <nav-control></nav-control>
   </nav-bar>
@@ -38,4 +38,4 @@
 </template>
 </polymer-element>
 
-<script type="application/dart" src="heap_map.dart"></script>
\ No newline at end of file
+<script type="application/dart" src="heap_map.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/heap_profile.html b/runtime/observatory/lib/src/elements/heap_profile.html
index fafdcfb..3d0bfec 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.html
+++ b/runtime/observatory/lib/src/elements/heap_profile.html
@@ -53,7 +53,7 @@
   <nav-bar>
     <top-nav-menu></top-nav-menu>
     <isolate-nav-menu isolate="{{ profile.isolate }}"></isolate-nav-menu>
-    <nav-menu link="{{ profile.isolate.relativeLink('allocationprofile') }}" anchor="allocation profile" last="{{ true }}"></nav-menu>
+    <nav-menu link="{{ makeLink('/allocation-profiler', profile.isolate) }}" anchor="allocation profile" last="{{ true }}"></nav-menu>
     <nav-refresh callback="{{ resetAccumulator }}" label="Reset Accumulator"></nav-refresh>
     <nav-refresh callback="{{ refreshGC }}" label="GC"></nav-refresh>
     <nav-refresh callback="{{ refresh }}"></nav-refresh>
diff --git a/runtime/observatory/lib/src/elements/io_view.html b/runtime/observatory/lib/src/elements/io_view.html
index 4072404..a63f010 100644
--- a/runtime/observatory/lib/src/elements/io_view.html
+++ b/runtime/observatory/lib/src/elements/io_view.html
@@ -20,7 +20,7 @@
 
       <ul class="list-group">
         <li class="list-group-item">
-          <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/http/servers'))}}">HTTP Servers</a>
+          <a on-click="{{ goto }}" _href="{{gotoLink('io/http/servers', isolate)}}">HTTP Servers</a>
         </li>
       </ul>
 
@@ -28,7 +28,7 @@
 
       <ul class="list-group">
         <li class="list-group-item">
-          <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/sockets'))}}">Sockets</a>
+          <a on-click="{{ goto }}" _href="{{gotoLink('io/sockets', isolate)}}">Sockets</a>
         </li>
       </ul>
 
@@ -36,7 +36,7 @@
 
       <ul class="list-group">
         <li class="list-group-item">
-          <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/websockets'))}}">WebSockets</a>
+          <a on-click="{{ goto }}" _href="{{gotoLink('io/websockets', isolate)}}">WebSockets</a>
         </li>
       </ul>
 
@@ -44,7 +44,7 @@
 
       <ul class="list-group">
         <li class="list-group-item">
-          <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/file/randomaccessfiles'))}}">Random Access Files</a>
+          <a on-click="{{ goto }}" _href="{{gotoLink('io/file/randomaccessfiles', isolate)}}">Random Access Files</a>
         </li>
       </ul>
 
@@ -52,7 +52,7 @@
 
       <ul class="list-group">
         <li class="list-group-item">
-          <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/processes'))}}">Processes</a>
+          <a on-click="{{ goto }}" _href="{{gotoLink('io/processes', isolate)}}">Processes</a>
         </li>
       </ul>
 
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index 5718cdb..5331b1e 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -152,39 +152,39 @@
         <br>
         <div class="memberItem">
           <div class="memberValue">
-            See <a on-click="{{ goto }}" _href="{{ gotoLink('/debugger' + isolate.link) }}">debugger</a>
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/debugger', isolate) }}">debugger</a>
           </div>
         </div>
         <div class="memberItem">
           <div class="memberValue">
-            See <a on-click="{{ goto }}" _href="{{ gotoLink('/class-tree' + isolate.link) }}">class hierarchy</a>
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/class-tree', isolate) }}">class hierarchy</a>
           </div>
         </div>
         <div class="memberItem">
           <div class="memberValue">
-            See <a on-click="{{ goto }}" _href="{{ gotoLink('/profiler' + isolate.link) }}">cpu profile</a>
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/profiler', isolate) }}">cpu profile</a>
           </div>
         </div>
         <div class="memberItem">
           <div class="memberValue">
-            See <a on-click="{{ goto }}" _href="{{ gotoLink('/allocation-profiler' + isolate.link) }}">allocation profile</a>
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/allocation-profiler', isolate) }}">allocation profile</a>
           </div>
         </div>
         <div class="memberItem">
           <div class="memberValue">
-            See <a on-click="{{ goto }}" _href="{{ gotoLink('/heap-map' + isolate.link) }}">heap map</a>
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/heap-map', isolate) }}">heap map</a>
           </div>
         </div>
         <div class="memberItem">
           <div class="memberValue">
-            See <a on-click="{{ goto }}" _href="{{ gotoLink(isolate.relativeLink('metrics')) }}">metrics</a>
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/metrics', isolate) }}">metrics</a>
           </div>
         </div>
         <!-- Temporarily disabled until UI for dart:io is acceptable.
         <template if="{{ isolate.ioEnabled }}">
           <div class="memberItem">
             <div class="memberValue">
-              See <a on-click="{{ goto }}" href="{{ gotoLink(isolate.relativeLink('io')) }}">dart:io</a>
+              See <a on-click="{{ goto }}" href="{{ gotoLink('/io', isolate) }}">dart:io</a>
             </div>
           </div>
         </template>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 9ac4ed8..615a855 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -99,13 +99,6 @@
             </div>
           </div>
         </div>
-        <div class="flex-item-50-percent">
-          <div class="memberItem">
-            <div class="memberValue">
-              See <a on-click="{{ goto }}" _href="{{ gotoLink(isolate.relativeLink('debug/breakpoints')) }}">breakpoints</a>
-            </div>
-          </div>
-        </div>
       </div>
     </div>
 
diff --git a/runtime/observatory/lib/src/elements/nav_bar.dart b/runtime/observatory/lib/src/elements/nav_bar.dart
index 9f5b0ed..75e7d66 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.dart
+++ b/runtime/observatory/lib/src/elements/nav_bar.dart
@@ -83,21 +83,6 @@
   @published bool last = false;
   @published Isolate isolate;
 
-  void isolateChanged(oldValue) {
-    notifyPropertyChange(#hashLinkWorkaround, 0, 1);
-  }
-
-  // TODO(turnidge): Figure out why polymer needs this function.
-  @reflectable
-  String get hashLinkWorkaround {
-    if (isolate != null) {
-      return isolate.link;
-    } else {
-      return '';
-    }
-  }
-  @reflectable set hashLinkWorkaround(var x) { /* silence polymer */ }
-
   IsolateNavMenuElement.created() : super.created();
 }
 
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index 9ffecd1..bb6c045 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -201,14 +201,14 @@
 
 <polymer-element name="isolate-nav-menu" extends="observatory-element">
   <template>
-    <nav-menu link="{{ hashLinkWorkaround }}" anchor="{{ isolate.name }}" last="{{ last }}">
-      <nav-menu-item link="{{ '/debugger' + isolate.link }}"
+    <nav-menu link="{{ makeLink('/inspect', isolate) }}" anchor="{{ isolate.name }}" last="{{ last }}">
+      <nav-menu-item link="{{ makeLink('/debugger', isolate) }}"
                      anchor="debugger"></nav-menu-item>
-      <nav-menu-item link="{{ '/profiler' + isolate.link }}"
+      <nav-menu-item link="{{ makeLink('/profiler', isolate) }}"
                      anchor="cpu profile"></nav-menu-item>
-      <nav-menu-item link="{{ '/allocation-profiler' + isolate.link }}"
+      <nav-menu-item link="{{ makeLink('/allocation-profiler', isolate) }}"
                      anchor="allocation profile"></nav-menu-item>
-      <nav-menu-item link="{{ '/heap-map' + isolate.link }}"
+      <nav-menu-item link="{{ makeLink('/heap-map', isolate) }}"
                      anchor="heap map"></nav-menu-item>
       <content></content>
     </nav-menu>
@@ -217,7 +217,7 @@
 
 <polymer-element name="library-nav-menu" extends="observatory-element">
   <template>
-    <nav-menu link="{{ library.link }}"
+    <nav-menu link="{{ makeLink('/inspect', library) }}"
               anchor="{{ library.name }}" last="{{ last }}">
       <content></content>
     </nav-menu>
@@ -226,7 +226,7 @@
 
 <polymer-element name="class-nav-menu" extends="observatory-element">
   <template>
-    <nav-menu link="{{ cls.link }}"
+    <nav-menu link="{{ makeLink('/inspect', cls) }}"
               anchor="{{ cls.name }}" last="{{ last }}">
       <content></content>
     </nav-menu>
@@ -320,7 +320,7 @@
       <div class="item">
         Isolate
         <a class="link" on-click="{{ goto }}"
-           _href="{{ event.isolate.link }}">{{ event.isolate.name }}</a>
+           _href="{{ gotoLink('/inspect', event.isolate) }}">{{ event.isolate.name }}</a>
         is paused
         <template if="{{ event.breakpoint != null }}">
           at breakpoint
diff --git a/runtime/observatory/lib/src/elements/observatory_element.dart b/runtime/observatory/lib/src/elements/observatory_element.dart
index b31ac94..9e9a363 100644
--- a/runtime/observatory/lib/src/elements/observatory_element.dart
+++ b/runtime/observatory/lib/src/elements/observatory_element.dart
@@ -7,6 +7,7 @@
 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.
@@ -91,9 +92,21 @@
     event.stopPropagation();
   }
 
+  String makeLink(String url, [ServiceObject obj]) {
+    if (obj != null) {
+      if (obj is Isolate) {
+        url = '${url}?isolateId=${Uri.encodeComponent(obj.id)}';
+      } else {
+        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) {
-    return app.locationManager.makeLink(url);
+  String gotoLink(String url, [ServiceObject obj]) {
+    return app.locationManager.makeLink(makeLink(url, obj));
   }
 
   String formatTimePrecise(double time) => Utils.formatTimePrecise(time);
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index b6f31ec..7e376f7 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -10,8 +10,8 @@
     <top-nav-menu></top-nav-menu>
     <isolate-nav-menu isolate="{{ script.isolate }}">
     </isolate-nav-menu>
-    <nav-menu link="{{ script.owningLibrary.link }}" anchor="{{ script.owningLibrary.name }}"></nav-menu>
-    <nav-menu link="{{ script.link }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
+    <nav-menu link="{{ makeLink('/inspect', script.owningLibrary) }}" anchor="{{ script.owningLibrary.name }}"></nav-menu>
+    <nav-menu link="{{ makeLink('/inspect', script) }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
     <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
     <nav-refresh callback="{{ refresh }}"></nav-refresh>
     <nav-control></nav-control>
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index 63f2449..f8ef42e 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -27,7 +27,7 @@
     if (ref == null) {
       return 'NULL REF';
     }
-    return gotoLink(ref.link);
+    return gotoLink('/inspect', ref);
   }
 
   String get serviceId {
diff --git a/runtime/observatory/lib/src/elements/service_view.dart b/runtime/observatory/lib/src/elements/service_view.dart
index 98ed51c..ad12afd 100644
--- a/runtime/observatory/lib/src/elements/service_view.dart
+++ b/runtime/observatory/lib/src/elements/service_view.dart
@@ -26,10 +26,6 @@
         HeapProfileElement element = new Element.tag('heap-profile');
         element.profile = object;
         return element;
-      case 'BreakpointList':
-        BreakpointListElement element = new Element.tag('breakpoint-list');
-        element.msg = object;
-        return element;
       case 'Class':
         ClassViewElement element = new Element.tag('class-view');
         element.cls = object;
diff --git a/runtime/observatory/lib/src/elements/service_view.html b/runtime/observatory/lib/src/elements/service_view.html
index 02a3ff8..b3254c0 100644
--- a/runtime/observatory/lib/src/elements/service_view.html
+++ b/runtime/observatory/lib/src/elements/service_view.html
@@ -1,5 +1,4 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="breakpoint_list.html">
 <link rel="import" href="class_view.html">
 <link rel="import" href="code_view.html">
 <link rel="import" href="context_view.html">
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index b22a887..f4ec057 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -4,8 +4,7 @@
 
 part of service;
 
-/// A [ServiceObject] is an object known to the VM service and is tied
-/// to an owning [Isolate].
+/// A [ServiceObject] represents a persistent object within the vm.
 abstract class ServiceObject extends Observable {
   static int LexicalSortName(ServiceObject o1, ServiceObject o2) {
     return o1.name.compareTo(o2.name);
@@ -90,9 +89,6 @@
             !isMirrorReference && !isWeakProperty && !isClosure);
   }
 
-  /// The complete service url of this object.
-  @reflectable String get link => _owner.relativeLink(_id);
-
   /// Has this object been fully loaded?
   bool get loaded => _loaded;
   bool _loaded = false;
@@ -282,19 +278,12 @@
 
   // Updates internal state from [map]. [map] can be a reference.
   void _update(ObservableMap map, bool mapIsRef);
-
-  String relativeLink(String id) {
-    assert(id != null);
-    return "${link}/${id}";
-  }
 }
 
 abstract class Coverage {
   // Following getters and functions will be provided by [ServiceObject].
-  ServiceObjectOwner get owner;
-  String get type;
-  VM get vm;
-  String relativeLink(String id);
+  String get id;
+  Isolate get isolate;
 
   /// Default handler for coverage data.
   void processCoverageData(List coverageData) {
@@ -311,8 +300,7 @@
     }
     return isolate.invokeRpcNoUpgrade('getCoverage', params).then(
         (ObservableMap map) {
-          var coverageOwner = (type == 'Isolate') ? this : owner;
-          var coverage = new ServiceObject._fromMap(coverageOwner, map);
+          var coverage = new ServiceObject._fromMap(isolate, map);
           assert(coverage.type == 'CodeCoverage');
           var coverageList = coverage['coverage'];
           assert(coverageList != null);
@@ -329,9 +317,6 @@
   /// The result may come from the cache.  The result will not necessarily
   /// be [loaded].
   ServiceObject getFromMap(ObservableMap map);
-
-  /// Creates a link to [id] relative to [this].
-  String relativeLink(String id);
 }
 
 /// State for a VM being inspected.
@@ -341,9 +326,6 @@
 
   @reflectable Iterable<Isolate> get isolates => _isolateCache.values;
 
-  @reflectable String get link => '$id';
-  @reflectable String relativeLink(String id) => '$id';
-
   @observable String version = 'unknown';
   @observable String targetCPU;
   @observable int architectureBits;
@@ -450,42 +432,6 @@
       });
   }
 
-  Future<ServiceObject> getDeprecated(String id) {
-    assert(id.startsWith('/') == false);
-    // Isolates are handled specially, since they can cache sub-objects.
-    if (id.startsWith(_isolatesPrefix)) {
-      String isolateId = _parseIsolateId(id);
-      String objectId = _parseObjectId(id);
-      return getIsolate(isolateId).then((isolate) {
-        if (isolate == null) {
-          // The isolate does not exist.  Return the VM object instead.
-          //
-          // TODO(turnidge): Generate a service error?
-          return this;
-        }
-        if (objectId == null) {
-          return isolate.reload();
-        } else {
-          return isolate.getDeprecated(objectId);
-        }
-      });
-    }
-
-    var obj = _cache[id];
-    if (obj != null) {
-      return obj.reload();
-    }
-
-    // Cache miss.  Get the object from the vm directly.
-    return _getAsMapDeprecated(id).then((ObservableMap map) {
-      var obj = new ServiceObject._fromMap(this, map);
-      if (obj.canCache) {
-        _cache.putIfAbsent(id, () => obj);
-      }
-      return obj;
-    });
-  }
-
   dynamic _reviver(dynamic key, dynamic value) {
     return value;
   }
@@ -527,31 +473,6 @@
     return new Future.value(map);
   }
 
-  /// Gets [id] as an [ObservableMap] from the service directly. If
-  /// an error occurs, the future is completed as an error with a
-  /// ServiceError or ServiceException. Therefore any chained then() calls
-  /// will only receive a map encoding a valid ServiceObject.
-  Future<ObservableMap> _getAsMapDeprecated(String id) {
-    return getStringDeprecated(id).then((response) {
-      var map = _parseJSON(response);
-      if (Tracer.current != null) {
-        Tracer.current.trace("Received response for ${id}", map:map);
-      }
-      return _processMap(map);
-    }).catchError((error) {
-      // ServiceError, forward to VM's ServiceError stream.
-      errors.add(error);
-      return new Future.error(error);
-    }, test: (e) => e is ServiceError).catchError((exception) {
-      // ServiceException, forward to VM's ServiceException stream.
-      exceptions.add(exception);
-      return new Future.error(exception);
-    }, test: (e) => e is ServiceException);
-  }
-
-  /// Get [id] as a [String] from the service directly. See [getAsMap].
-  Future<String> getStringDeprecated(String id);
-
   // Implemented in subclass.
   Future<String> invokeRpcRaw(String method, Map params);
 
@@ -592,6 +513,10 @@
     return invokeRpcNoUpgrade('getVM', {});
   }
 
+  Future<ServiceObject> getFlagList() {
+    return invokeRpc('getFlagList', {});
+  }
+
   /// Force the VM to disconnect.
   void disconnect();
   /// Completes when the VM first connects.
@@ -754,8 +679,7 @@
     var result = [];
     for (var v in graph.getMostRetained(classId: classId, limit: limit)) {
       var address = v.addressForWordSize(isolate.vm.architectureBits ~/ 8);
-      result.add(isolate.getDeprecated(
-          'address/${address.toRadixString(16)}?ref=true').then((obj) {
+      result.add(isolate.getObjectByAddress(address.toRadixString(16)).then((obj) {
         obj.retainedSize = v.retainedSize;
         return new Future(() => obj);
       }));
@@ -772,8 +696,6 @@
   @reflectable Isolate get isolate => this;
   @observable ObservableMap counters = new ObservableMap();
 
-  String get link => '/${_id}';
-
   @observable ServiceEvent pauseEvent = null;
   bool get _isPaused => pauseEvent != null;
 
@@ -789,9 +711,6 @@
     assert(owner is VM);
   }
 
-  /// Creates a link to [id] relative to [this].
-  @reflectable String relativeLink(String id) => '/${this.id}/$id';
-
   static const TAG_ROOT_ID = 'code/tag-0';
 
   /// Returns the Code object for the root tag.
@@ -890,25 +809,8 @@
     return obj;
   }
 
-  Future<ServiceObject> getDeprecated(String id) {
-    // Do not allow null ids or empty ids.
-    assert(id != null && id != '');
-    var obj = _cache[id];
-    if (obj != null) {
-      return obj.reload();
-    }
-    // Cache miss.  Get the object from the vm directly.
-    return vm._getAsMapDeprecated(relativeLink(id)).then((ObservableMap map) {
-      var obj = new ServiceObject._fromMap(this, map);
-      if (obj.canCache) {
-        _cache.putIfAbsent(id, () => obj);
-      }
-      return obj;
-    });
-  }
-
   Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
-    params['isolate'] = id;
+    params['isolateId'] = id;
     return vm.invokeRpcNoUpgrade(method, params);
   }
 
@@ -1327,6 +1229,14 @@
     return invokeRpc('getInstances', params);
   }
 
+  Future<ServiceObject> getObjectByAddress(String address, [bool ref=true]) {
+    Map params = {
+      'address': address,
+      'ref': ref,
+    };
+    return invokeRpc('getObjectByAddress', params);
+  }
+
   final ObservableMap<String, ServiceMetric> dartMetrics =
       new ObservableMap<String, ServiceMetric>();
 
diff --git a/runtime/observatory/observatory.gypi b/runtime/observatory/observatory.gypi
index bf4723a..1eb2ba2 100644
--- a/runtime/observatory/observatory.gypi
+++ b/runtime/observatory/observatory.gypi
@@ -67,8 +67,6 @@
         'lib/src/app/view_model.dart',
         'lib/src/elements/action_link.dart',
         'lib/src/elements/action_link.html',
-        'lib/src/elements/breakpoint_list.dart',
-        'lib/src/elements/breakpoint_list.html',
         'lib/src/elements/class_ref.dart',
         'lib/src/elements/class_ref.html',
         'lib/src/elements/class_tree.dart',
@@ -107,6 +105,8 @@
         'lib/src/elements/function_ref.html',
         'lib/src/elements/function_view.dart',
         'lib/src/elements/function_view.html',
+        'lib/src/elements/general_error.dart',
+        'lib/src/elements/general_error.html',
         'lib/src/elements/heap_map.dart',
         'lib/src/elements/heap_map.html',
         'lib/src/elements/heap_profile.dart',
diff --git a/runtime/tests/vm/dart/bad_snapshot b/runtime/tests/vm/dart/bad_snapshot
new file mode 100644
index 0000000..9b1a92d
--- /dev/null
+++ b/runtime/tests/vm/dart/bad_snapshot
Binary files differ
diff --git a/runtime/tests/vm/dart/snapshot_version_test.dart b/runtime/tests/vm/dart/snapshot_version_test.dart
new file mode 100644
index 0000000..2dcde10
--- /dev/null
+++ b/runtime/tests/vm/dart/snapshot_version_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:io";
+import "package:expect/expect.dart";
+
+main() {
+  var result = Process.runSync(Platform.executable,
+      [Platform.script.resolve('./bad_snapshot').toFilePath()]);
+  print("=== stdout ===\n ${result.stdout}");
+  print("=== stderr ===\n ${result.stderr}");
+  Expect.equals(253, result.exitCode);
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index d2d66d6..dfe5f584 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -85,3 +85,6 @@
 
 [ $compiler == none && $runtime == ContentShellOnAndroid ]
 dart/byte_array_test: RuntimeError # Issue 17612
+
+[ $runtime != vm ]
+dart/snapshot_version_test: SkipByDesign  # Spawns processes
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index f0de423..32719ac 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -24,6 +24,7 @@
   V(Function_apply, 2)                                                         \
   V(FunctionImpl_equals, 2)                                                    \
   V(FunctionImpl_hashCode, 1)                                                  \
+  V(FunctionImpl_clone, 1)                                                     \
   V(AbstractType_toString, 1)                                                  \
   V(Identical_comparison, 2)                                                   \
   V(Integer_bitAndFromInteger, 2)                                              \
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 6d97ba5..38b5f2f 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -639,8 +639,8 @@
 DEFINE_RUNTIME_ENTRY(ReThrow, 2) {
   const Instance& exception =
       Instance::CheckedHandle(isolate, arguments.ArgAt(0));
-  const Instance& stacktrace =
-      Instance::CheckedHandle(isolate, arguments.ArgAt(1));
+  const Stacktrace& stacktrace =
+      Stacktrace::CheckedHandle(isolate, arguments.ArgAt(1));
   Exceptions::ReThrow(isolate, exception, stacktrace);
 }
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 77af93c..04eabbb 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -761,7 +761,7 @@
   if (obj.IsNull()) {
     RETURN_TYPE_ERROR(isolate, exception, Instance);
   }
-  const Instance& stacktrace = Instance::Handle(isolate);
+  const Stacktrace& stacktrace = Stacktrace::Handle(isolate);
   return Api::NewHandle(isolate, UnhandledException::New(obj, stacktrace));
 }
 
@@ -4373,16 +4373,16 @@
   ApiState* state = isolate->api_state();
   ASSERT(state != NULL);
   const Instance* saved_exception;
-  const Instance* saved_stacktrace;
+  const Stacktrace* saved_stacktrace;
   {
     NoGCScope no_gc;
     RawInstance* raw_exception =
         Api::UnwrapInstanceHandle(isolate, exception).raw();
-    RawInstance* raw_stacktrace =
-        Api::UnwrapInstanceHandle(isolate, stacktrace).raw();
+    RawStacktrace* raw_stacktrace =
+        Api::UnwrapStacktraceHandle(isolate, stacktrace).raw();
     state->UnwindScopes(isolate->top_exit_frame_info());
     saved_exception = &Instance::Handle(raw_exception);
-    saved_stacktrace = &Instance::Handle(raw_stacktrace);
+    saved_stacktrace = &Stacktrace::Handle(raw_stacktrace);
   }
   Exceptions::ReThrow(isolate, *saved_exception, *saved_stacktrace);
   return Api::NewError("Exception was not re thrown, internal error");
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 4cb32fc..d863b24 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -361,7 +361,7 @@
 
 static void ThrowExceptionHelper(Isolate* isolate,
                                  const Instance& incoming_exception,
-                                 const Instance& existing_stacktrace,
+                                 const Stacktrace& existing_stacktrace,
                                  const bool is_rethrow) {
   bool use_preallocated_stacktrace = false;
   Instance& exception = Instance::Handle(isolate, incoming_exception.raw());
@@ -426,7 +426,7 @@
         stacktrace = Stacktrace::New(code_array, pc_offset_array);
       } else {
         ASSERT(is_rethrow);
-        stacktrace ^= existing_stacktrace.raw();
+        stacktrace = existing_stacktrace.raw();
         if (pc_offset_array.Length() != 0) {
           // Skip the first frame during a rethrow. This is the catch clause
           // with the rethrow statement, which is not part of the original
@@ -573,13 +573,13 @@
     isolate->debugger()->SignalExceptionThrown(exception);
   }
   // Null object is a valid exception object.
-  ThrowExceptionHelper(isolate, exception, Instance::Handle(isolate), false);
+  ThrowExceptionHelper(isolate, exception, Stacktrace::Handle(isolate), false);
 }
 
 
 void Exceptions::ReThrow(Isolate* isolate,
                          const Instance& exception,
-                         const Instance& stacktrace) {
+                         const Stacktrace& stacktrace) {
   // Null object is a valid exception object.
   ThrowExceptionHelper(isolate, exception, stacktrace, true);
 }
@@ -593,7 +593,7 @@
     // rethrow the exception in the normal fashion.
     const UnhandledException& uhe = UnhandledException::Cast(error);
     const Instance& exc = Instance::Handle(isolate, uhe.exception());
-    const Instance& stk = Instance::Handle(isolate, uhe.stacktrace());
+    const Stacktrace& stk = Stacktrace::Handle(isolate, uhe.stacktrace());
     Exceptions::ReThrow(isolate, exc, stk);
   } else {
     // Return to the invocation stub and return this error object.  The
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index cf0eb98..9743ca8 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -24,6 +24,7 @@
 class RawString;
 class Script;
 class StackFrame;
+class Stacktrace;
 class String;
 
 class Exceptions : AllStatic {
@@ -33,7 +34,7 @@
   static void Throw(Isolate* isolate, const Instance& exception);
   static void ReThrow(Isolate* isolate,
                       const Instance& exception,
-                      const Instance& stacktrace);
+                      const Stacktrace& stacktrace);
   static void PropagateError(const Error& error);
 
   // Helpers to create and throw errors.
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 009c60c..afc250d 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1075,13 +1075,13 @@
   //
   // We distinguish those kinds of nodes via is_regular_return().
   //
-  if (function.is_async_closure() &&
+  if (function.IsAsyncClosure() &&
       (node->return_type() == ReturnNode::kRegular)) {
     // Temporary store the computed return value.
     Do(BuildStoreExprTemp(return_value));
 
-    LocalVariable* rcv_var = node->scope()->LookupVariable(
-        Symbols::AsyncCompleter(), false);
+    LocalVariable* rcv_var =
+        node->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
     ASSERT(rcv_var != NULL && rcv_var->is_captured());
     ZoneGrowableArray<PushArgumentInstr*>* arguments =
         new(I) ZoneGrowableArray<PushArgumentInstr*>(2);
@@ -1109,10 +1109,9 @@
     UnchainContexts(current_context_level);
   }
 
-
   AddReturnExit(node->token_pos(), return_value);
 
-  if (function.is_async_closure() &&
+  if ((function.IsAsyncClosure() || function.IsSyncGenClosure()) &&
       (node->return_type() == ReturnNode::kContinuationTarget)) {
     JoinEntryInstr* const join = new(I) JoinEntryInstr(
         owner()->AllocateBlockId(), owner()->try_index());
@@ -1484,6 +1483,62 @@
 }
 
 
+void EffectGraphVisitor::BuildYieldJump(LocalVariable* old_context,
+                                        LocalVariable* iterator_param,
+                                        const intptr_t old_ctx_level,
+                                        JoinEntryInstr* target) {
+  // Building a jump consists of the following actions:
+  // * Load the generator body's iterator parameter (:iterator)
+  //   from the current context into a temporary.
+  // * Restore the old context from :await_cxt_var.
+  // * Copy the iterator saved above into the restored context.
+  // * Append a Goto to the target's join.
+  ASSERT((iterator_param != NULL) && iterator_param->is_captured());
+  ASSERT((old_context != NULL) && old_context->is_captured());
+  // Before restoring the context we need to temporarily save the
+  // iterator parameter.
+  LocalVariable* temp_iterator_var =
+      EnterTempLocalScope(Bind(BuildLoadLocal(*iterator_param)));
+
+  // Restore the saved continuation context, i.e. the context that was
+  // saved into :await_ctx_var before the closure suspended.
+  BuildRestoreContext(*old_context);
+
+  // Store the continuation result and continuation error values into
+  // the restored context.
+
+  // FlowGraphBuilder is at top context level, but the continuation
+  // target has possibly been recorded in a nested context (old_ctx_level).
+  // We need to unroll manually here.
+  intptr_t delta =
+      old_ctx_level - iterator_param->owner()->context_level();
+  ASSERT(delta >= 0);
+  Value* context = Bind(BuildCurrentContext());
+  while (delta-- > 0) {
+    context = Bind(new(I) LoadFieldInstr(
+        context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()),
+        Scanner::kNoSourcePos));
+  }
+  LocalVariable* temp_context_var = EnterTempLocalScope(context);
+
+  Value* context_val = Bind(new(I) LoadLocalInstr(*temp_context_var));
+  Value* store_val = Bind(new(I) LoadLocalInstr(*temp_iterator_var));
+  StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr(
+      Context::variable_offset(iterator_param->index()),
+      context_val,
+      store_val,
+      kEmitStoreBarrier,
+      Scanner::kNoSourcePos);
+  Do(store);
+
+  Do(ExitTempLocalScope(temp_context_var));
+  Do(ExitTempLocalScope(temp_iterator_var));
+
+  // Goto saved join.
+  Goto(target);
+}
+
+
 void EffectGraphVisitor::BuildAwaitJump(LocalVariable* old_context,
                                         LocalVariable* continuation_result,
                                         LocalVariable* continuation_error,
@@ -1491,31 +1546,37 @@
                                         const intptr_t old_ctx_level,
                                         JoinEntryInstr* target) {
   // Building a jump consists of the following actions:
-  // * Record the current continuation result in a temporary.
-  // * Restore the old context.
-  // * Overwrite the old context's continuation result with the temporary.
+  // * Load the current continuation result parameter (:async_result)
+  //   and continuation error parameter (:async_error_param) from
+  //   the current context into temporaries.
+  // * Restore the old context from :await_cxt_var.
+  // * Copy the result and error parameters saved above into the restored
+  //   context.
   // * Append a Goto to the target's join.
   ASSERT((continuation_result != NULL) && continuation_result->is_captured());
   ASSERT((continuation_error != NULL) && continuation_error->is_captured());
   ASSERT((old_context != NULL) && old_context->is_captured());
   // Before restoring the continuation context we need to temporary save the
   // result and error parameter.
-  LocalVariable* temp_result_var = EnterTempLocalScope(
-      Bind(BuildLoadLocal(*continuation_result)));
-  LocalVariable* temp_error_var = EnterTempLocalScope(
-      Bind(BuildLoadLocal(*continuation_error)));
-  LocalVariable* temp_stack_trace_var = EnterTempLocalScope(
-      Bind(BuildLoadLocal(*continuation_stack_trace)));
-  // Restore the saved continuation context.
+  LocalVariable* temp_result_var =
+      EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_result)));
+  LocalVariable* temp_error_var =
+      EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_error)));
+  LocalVariable* temp_stack_trace_var =
+      EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_stack_trace)));
+
+  // Restore the saved continuation context, i.e. the context that was
+  // saved into :await_ctx_var before the closure suspended.
   BuildRestoreContext(*old_context);
 
-  // Pass over the continuation result.
+  // Store the continuation result and continuation error values into
+  // the restored context.
 
   // FlowGraphBuilder is at top context level, but the await target has possibly
   // been recorded in a nested context (old_ctx_level). We need to unroll
   // manually here.
-  intptr_t delta = old_ctx_level -
-                   continuation_result->owner()->context_level();
+  intptr_t delta =
+      old_ctx_level - continuation_result->owner()->context_level();
   ASSERT(delta >= 0);
   Value* context = Bind(BuildCurrentContext());
   while (delta-- > 0) {
@@ -3702,6 +3763,7 @@
 //                            label: SourceLabel }
 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
   LocalScope* scope = node->scope();
+  const Function& function = owner()->function();
   const intptr_t num_context_variables =
       (scope != NULL) ? scope->num_context_variables() : 0;
   const bool is_top_level_sequence =
@@ -3734,7 +3796,6 @@
     // the captured parameters from the frame into the context.
     if (is_top_level_sequence) {
       ASSERT(scope->context_level() == 1);
-      const Function& function = owner()->function();
       const int num_params = function.NumParameters();
       int param_frame_index = (num_params == function.num_fixed_parameters()) ?
           (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp;
@@ -3772,7 +3833,6 @@
 
   // This check may be deleted if the generated code is leaf.
   // Native functions don't need a stack check at entry.
-  const Function& function = owner()->function();
   if (is_top_level_sequence && !function.is_native()) {
     // Always allocate CheckOverflowInstr so that deopt-ids match regardless
     // if we inline or not.
@@ -3789,7 +3849,6 @@
   }
 
   if (Isolate::Current()->TypeChecksEnabled() && is_top_level_sequence) {
-    const Function& function = owner()->function();
     const int num_params = function.NumParameters();
     int pos = 0;
     if (function.IsConstructor()) {
@@ -3818,10 +3877,12 @@
   }
 
   // Continuation part:
-  // If this node sequence is the body of an async closure leave room for a
-  // preamble. The preamble is generated after visiting the body.
+  // If this node sequence is the body of a function with continuations,
+  // leave room for a preamble.
+  // The preamble is generated after visiting the body.
   GotoInstr* preamble_start = NULL;
-  if (is_top_level_sequence && (owner()->function().is_async_closure())) {
+  if (is_top_level_sequence &&
+      (function.IsAsyncClosure() || function.IsSyncGenClosure())) {
     JoinEntryInstr* preamble_end = new(I) JoinEntryInstr(
         owner()->AllocateBlockId(), owner()->try_index());
     ASSERT(exit() != NULL);
@@ -3844,33 +3905,28 @@
   }
 
   // Continuation part:
-  // After generating the CFG for the body we can create the preamble because we
-  // know exactly how many continuation states we need.
-  if (is_top_level_sequence && (owner()->function().is_async_closure())) {
+  // After generating the CFG for the body we can create the preamble
+  // because we know exactly how many continuation states we need.
+  if (is_top_level_sequence &&
+      (function.IsAsyncClosure() || function.IsSyncGenClosure())) {
     ASSERT(preamble_start != NULL);
     // We are at the top level. Fetch the corresponding scope.
     LocalScope* top_scope = node->scope();
     LocalVariable* jump_var = top_scope->LookupVariable(
         Symbols::AwaitJumpVar(), false);
     ASSERT(jump_var != NULL && jump_var->is_captured());
-
     Instruction* saved_entry = entry_;
     Instruction* saved_exit = exit_;
     entry_ = NULL;
     exit_ = NULL;
 
-    LoadLocalNode* load_jump_count = new(I) LoadLocalNode(
-        Scanner::kNoSourcePos, jump_var);
+    LoadLocalNode* load_jump_count =
+        new(I) LoadLocalNode(Scanner::kNoSourcePos, jump_var);
     ComparisonNode* check_jump_count;
     const intptr_t num_await_states = owner()->await_joins()->length();
+
     LocalVariable* old_context = top_scope->LookupVariable(
         Symbols::AwaitContextVar(), false);
-    LocalVariable* continuation_result = top_scope->LookupVariable(
-        Symbols::AsyncOperationParam(), false);
-    LocalVariable* continuation_error = top_scope->LookupVariable(
-        Symbols::AsyncOperationErrorParam(), false);
-    LocalVariable* continuation_stack_trace = top_scope->LookupVariable(
-        Symbols::AsyncOperationStackTraceParam(), false);
     for (intptr_t i = 0; i < num_await_states; i++) {
       check_jump_count = new(I) ComparisonNode(
           Scanner::kNoSourcePos,
@@ -3883,14 +3939,32 @@
       EffectGraphVisitor for_true(owner());
       EffectGraphVisitor for_false(owner());
 
-      for_true.BuildAwaitJump(old_context,
-                              continuation_result,
-                              continuation_error,
-                              continuation_stack_trace,
-                              (*owner()->await_levels())[i],
-                              (*owner()->await_joins())[i]);
-      Join(for_test, for_true, for_false);
+      if (function.IsAsyncClosure()) {
+        LocalVariable* result_param =
+            top_scope->LookupVariable(Symbols::AsyncOperationParam(), false);
+        LocalVariable* error_param =
+            top_scope->LookupVariable(Symbols::AsyncOperationErrorParam(),
+                                      false);
+        LocalVariable* stack_trace_param =
+            top_scope->LookupVariable(Symbols::AsyncOperationStackTraceParam(),
+                                      false);
+        for_true.BuildAwaitJump(old_context,
+                                result_param,
+                                error_param,
+                                stack_trace_param,
+                                (*owner()->await_levels())[i],
+                                (*owner()->await_joins())[i]);
+      } else {
+        ASSERT(function.IsSyncGenClosure());
+        LocalVariable* iterator_param =
+            top_scope->LookupVariable(Symbols::IteratorParameter(), false);
+        for_true.BuildYieldJump(old_context,
+                                iterator_param,
+                                (*owner()->await_levels())[i],
+                                (*owner()->await_joins())[i]);
+      }
 
+      Join(for_test, for_true, for_false);
       if (i == 0) {
         // Manually link up the preamble start.
         preamble_start->previous()->set_next(for_test.entry());
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index fa337d1..4168459 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -467,6 +467,11 @@
 
   void BuildLetTempExpressions(LetNode* node);
 
+  void BuildYieldJump(LocalVariable* old_context,
+                      LocalVariable* iterator_param,
+                      const intptr_t old_ctx_level,
+                      JoinEntryInstr* target);
+
   void BuildAwaitJump(LocalVariable* old_context,
                       LocalVariable* continuation_result,
                       LocalVariable* continuation_error,
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 1649ab2..ddd24f3 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -61,8 +61,8 @@
 #if defined(DEBUG)
   // Pattern for unused new space and swept old space.
   static const uint64_t kZap64Bits = 0xf3f3f3f3f3f3f3f3;
-  static const uint32_t kZap32Bits = static_cast<uint32_t>(kZap64Bits);
-  static const uint8_t kZapByte = static_cast<uint8_t>(kZap64Bits);
+  static const uint32_t kZap32Bits = 0xf3f3f3f3;
+  static const uint8_t kZapByte = 0xf3;
 #endif  // DEBUG
 
   ~Heap();
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index b525d7f..d4ae6a1 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -21,12 +21,10 @@
     : open_objects_(0),
       buffer_(buf_size),
       reply_port_(ILLEGAL_PORT),
-      command_(""),
-      arguments_(NULL),
-      num_arguments_(0),
-      option_keys_(NULL),
-      option_values_(NULL),
-      num_options_(0) {
+      method_(""),
+      param_keys_(NULL),
+      param_values_(NULL),
+      num_params_(0) {
 }
 
 
@@ -36,89 +34,35 @@
 
 void JSONStream::Setup(Zone* zone,
                        Dart_Port reply_port,
-                       const GrowableObjectArray& path,
-                       const Array& option_keys,
-                       const Array& option_values) {
+                       const String& method,
+                       const Array& param_keys,
+                       const Array& param_values) {
   set_reply_port(reply_port);
+  method_ = method.ToCString();
 
-  // Setup JSONStream arguments and options. The arguments and options
-  // are zone allocated and will be freed immediately after handling the
-  // message.
-  const char** arguments = zone->Alloc<const char*>(path.Length());
   String& string_iterator = String::Handle();
-  for (intptr_t i = 0; i < path.Length(); i++) {
-    string_iterator ^= path.At(i);
-    arguments[i] = zone->MakeCopyOfString(string_iterator.ToCString());
-    if (i == 0) {
-      command_ = arguments[i];
-    }
-  }
-  SetArguments(arguments, path.Length());
-  if (option_keys.Length() > 0) {
-    const char** option_keys_native =
-        zone->Alloc<const char*>(option_keys.Length());
-    const char** option_values_native =
-        zone->Alloc<const char*>(option_keys.Length());
-    for (intptr_t i = 0; i < option_keys.Length(); i++) {
-      string_iterator ^= option_keys.At(i);
-      option_keys_native[i] =
+  if (param_keys.Length() > 0) {
+    ASSERT(param_keys.Length() == param_values.Length());
+    const char** param_keys_native =
+        zone->Alloc<const char*>(param_keys.Length());
+    const char** param_values_native =
+        zone->Alloc<const char*>(param_keys.Length());
+    for (intptr_t i = 0; i < param_keys.Length(); i++) {
+      string_iterator ^= param_keys.At(i);
+      param_keys_native[i] =
           zone->MakeCopyOfString(string_iterator.ToCString());
-      string_iterator ^= option_values.At(i);
-      option_values_native[i] =
+      string_iterator ^= param_values.At(i);
+      param_values_native[i] =
           zone->MakeCopyOfString(string_iterator.ToCString());
     }
-    SetOptions(option_keys_native, option_values_native, option_keys.Length());
+    SetParams(param_keys_native, param_values_native, param_keys.Length());
   }
   if (FLAG_trace_service) {
     Isolate* isolate = Isolate::Current();
     ASSERT(isolate != NULL);
     const char* isolate_name = isolate->name();
-    OS::Print("Isolate %s processing service request %s",
-              isolate_name, command_);
-    for (intptr_t i = 1; i < num_arguments(); i++) {
-      OS::Print("/%s", GetArgument(i));
-    }
-    OS::Print("\n");
-    setup_time_micros_ = OS::GetCurrentTimeMicros();
-  }
-}
-
-
-void JSONStream::SetupNew(Zone* zone,
-                          Dart_Port reply_port,
-                          const String& method,
-                          const Array& option_keys,
-                          const Array& option_values) {
-  set_reply_port(reply_port);
-  command_ = method.ToCString();
-
-  String& string_iterator = String::Handle();
-  if (option_keys.Length() > 0) {
-    ASSERT(option_keys.Length() == option_values.Length());
-    const char** option_keys_native =
-        zone->Alloc<const char*>(option_keys.Length());
-    const char** option_values_native =
-        zone->Alloc<const char*>(option_keys.Length());
-    for (intptr_t i = 0; i < option_keys.Length(); i++) {
-      string_iterator ^= option_keys.At(i);
-      option_keys_native[i] =
-          zone->MakeCopyOfString(string_iterator.ToCString());
-      string_iterator ^= option_values.At(i);
-      option_values_native[i] =
-          zone->MakeCopyOfString(string_iterator.ToCString());
-    }
-    SetOptions(option_keys_native, option_values_native, option_keys.Length());
-  }
-  if (FLAG_trace_service) {
-    Isolate* isolate = Isolate::Current();
-    ASSERT(isolate != NULL);
-    const char* isolate_name = isolate->name();
-    OS::Print("Isolate %s processing service request %s",
-              isolate_name, command_);
-    for (intptr_t i = 1; i < num_arguments(); i++) {
-      OS::Print("/%s", GetArgument(i));
-    }
-    OS::Print("\n");
+    OS::Print("Isolate %s processing service request %s\n",
+              isolate_name, method_);
     setup_time_micros_ = OS::GetCurrentTimeMicros();
   }
 }
@@ -151,36 +95,32 @@
     Isolate* isolate = Isolate::Current();
     ASSERT(isolate != NULL);
     const char* isolate_name = isolate->name();
-    OS::Print("Isolate %s processed service request %s",
-              isolate_name, command_);
-    for (intptr_t i = 1; i < num_arguments(); i++) {
-      OS::Print("/%s", GetArgument(i));
-    }
-    OS::Print(" in %" Pd64" us.\n", process_delta_micros);
+    OS::Print("Isolate %s processed service request %s in %" Pd64" us.\n",
+              isolate_name, method_, process_delta_micros);
   }
 }
 
 
-const char* JSONStream::LookupOption(const char* key) const {
-  for (int i = 0; i < num_options(); i++) {
-    if (!strcmp(key, option_keys_[i])) {
-      return option_values_[i];
+const char* JSONStream::LookupParam(const char* key) const {
+  for (int i = 0; i < num_params(); i++) {
+    if (!strcmp(key, param_keys_[i])) {
+      return param_values_[i];
     }
   }
   return NULL;
 }
 
 
-bool JSONStream::HasOption(const char* key) const {
+bool JSONStream::HasParam(const char* key) const {
   ASSERT(key);
-  return LookupOption(key) != NULL;
+  return LookupParam(key) != NULL;
 }
 
 
-bool JSONStream::OptionIs(const char* key, const char* value) const {
+bool JSONStream::ParamIs(const char* key, const char* value) const {
   ASSERT(key);
   ASSERT(value);
-  const char* key_value = LookupOption(key);
+  const char* key_value = LookupParam(key);
   return (key_value != NULL) && (strcmp(key_value, value) == 0);
 }
 
@@ -411,22 +351,12 @@
 }
 
 
-void JSONStream::SetArguments(const char** arguments, intptr_t num_arguments) {
-  if (num_arguments > 0) {
-    // Set command.
-    command_ = arguments[0];
-  }
-  arguments_ = arguments;
-  num_arguments_ = num_arguments;
-}
-
-
-void JSONStream::SetOptions(const char** option_keys,
-                            const char** option_values,
-                            intptr_t num_options) {
-  option_keys_ = option_keys;
-  option_values_ = option_values;
-  num_options_ = num_options;
+void JSONStream::SetParams(const char** param_keys,
+                           const char** param_values,
+                           intptr_t num_params) {
+  param_keys_ = param_keys;
+  param_values_ = param_values;
+  num_params_ = num_params;
 }
 
 
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 56ecbcc..b15c3d5 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -31,15 +31,9 @@
 
   void Setup(Zone* zone,
              Dart_Port reply_port,
-             const GrowableObjectArray& path,
-             const Array& option_keys,
-             const Array& option_values);
-
-  void SetupNew(Zone* zone,
-                Dart_Port reply_port,
-                const String& method,
-                const Array& param_keys,
-                const Array& param_values);
+             const String& method,
+             const Array& param_keys,
+             const Array& param_values);
 
   void PostReply();
 
@@ -47,40 +41,31 @@
   const char* ToCString() { return buffer_.buf(); }
 
   void set_reply_port(Dart_Port port);
-  void SetArguments(const char** arguments, intptr_t num_arguments);
-  void SetOptions(const char** option_keys, const char** option_values,
-                  intptr_t num_options);
+
+  void SetParams(const char** param_keys, const char** param_values,
+                 intptr_t num_params);
 
   Dart_Port reply_port() const { return reply_port_; }
 
-  intptr_t num_arguments() const { return num_arguments_; }
-  const char* GetArgument(intptr_t i) const {
-    return arguments_[i];
+  intptr_t num_params() const { return num_params_; }
+  const char* GetParamKey(intptr_t i) const {
+    return param_keys_[i];
+  }
+  const char* GetParamValue(intptr_t i) const {
+    return param_values_[i];
   }
 
-  // TODO(turnidge): Rename "options" to "params".  That is the more
-  // appropriate name for json rpc.
-  intptr_t num_options() const { return num_options_; }
-  const char* GetOptionKey(intptr_t i) const {
-    return option_keys_[i];
-  }
-  const char* GetOptionValue(intptr_t i) const {
-    return option_values_[i];
-  }
+  const char* LookupParam(const char* key) const;
 
-  const char* LookupOption(const char* key) const;
+  bool HasParam(const char* key) const;
 
-  bool HasOption(const char* key) const;
-
-  // Returns true if there is an option with key and value, false
+  // Returns true if there is an param with key and value, false
   // otherwise.
-  bool OptionIs(const char* key, const char* value) const;
+  bool ParamIs(const char* key, const char* value) const;
 
-  // TODO(turnidge): Rename "command" to "method".  Better name for json rpc.
-  const char* command() const { return command_; }
-  const char** arguments() const { return arguments_; }
-  const char** option_keys() const { return option_keys_; }
-  const char** option_values() const { return option_values_; }
+  const char* method() const { return method_; }
+  const char** param_keys() const { return param_keys_; }
+  const char** param_values() const { return param_values_; }
 
  private:
   void Clear();
@@ -134,12 +119,10 @@
   intptr_t open_objects_;
   TextBuffer buffer_;
   Dart_Port reply_port_;
-  const char* command_;
-  const char** arguments_;
-  intptr_t num_arguments_;
-  const char** option_keys_;
-  const char** option_values_;
-  intptr_t num_options_;
+  const char* method_;
+  const char** param_keys_;
+  const char** param_values_;
+  intptr_t num_params_;
   int64_t setup_time_micros_;
 
   friend class JSONObject;
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index cf65040..b7c25da 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -390,25 +390,19 @@
 }
 
 
-TEST_CASE(JSON_JSONStream_Options) {
-  const char* arguments[] = {"a", "b", "c"};
-  const char* option_keys[] = {"dog", "cat"};
-  const char* option_values[] = {"apple", "banana"};
+TEST_CASE(JSON_JSONStream_Params) {
+  const char* param_keys[] = {"dog", "cat"};
+  const char* param_values[] = {"apple", "banana"};
 
   JSONStream js;
-  EXPECT(js.num_arguments() == 0);
-  js.SetArguments(&arguments[0], 3);
-  EXPECT(js.num_arguments() == 3);
-  EXPECT_STREQ("a", js.command());
-
-  EXPECT(js.num_options() == 0);
-  js.SetOptions(&option_keys[0], &option_values[0], 2);
-  EXPECT(js.num_options() == 2);
-  EXPECT(!js.HasOption("lizard"));
-  EXPECT(js.HasOption("dog"));
-  EXPECT(js.HasOption("cat"));
-  EXPECT(js.OptionIs("cat", "banana"));
-  EXPECT(!js.OptionIs("dog", "banana"));
+  EXPECT(js.num_params() == 0);
+  js.SetParams(&param_keys[0], &param_values[0], 2);
+  EXPECT(js.num_params() == 2);
+  EXPECT(!js.HasParam("lizard"));
+  EXPECT(js.HasParam("dog"));
+  EXPECT(js.HasParam("cat"));
+  EXPECT(js.ParamIs("cat", "banana"));
+  EXPECT(!js.ParamIs("dog", "banana"));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 8bb0a39..e774599 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5584,7 +5584,7 @@
 
 bool Function::CanBeInlined() const {
   return is_inlinable() &&
-         !is_async_closure() &&
+         !is_generated_body() &&
          HasCode() &&
          !Isolate::Current()->debugger()->HasBreakpoint(*this);
 }
@@ -6111,7 +6111,7 @@
   result.set_is_debuggable(true);  // Will be computed later.
   result.set_is_intrinsic(false);
   result.set_is_redirecting(false);
-  result.set_is_async_closure(false);
+  result.set_is_generated_body(false);
   result.set_always_inline(false);
   result.set_is_polymorphic_target(false);
   result.set_owner(owner);
@@ -12788,7 +12788,23 @@
 
 
 const char* ContextScope::ToCString() const {
-  return "ContextScope";
+  const char* format =
+      "%s\nvar %s  token-pos %" Pd "  ctx lvl %" Pd "  index %" Pd "";
+  const char* prev_cstr = "ContextScope:";
+  String& name = String::Handle();
+  for (int i = 0; i < num_variables(); i++) {
+    name = NameAt(i);
+    const char* cname = name.ToCString();
+    intptr_t pos = TokenIndexAt(i);
+    intptr_t idx = ContextIndexAt(i);
+    intptr_t lvl = ContextLevelAt(i);
+    intptr_t len =
+        OS::SNPrint(NULL, 0, format, prev_cstr, cname, pos, lvl, idx) + 1;
+    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+    OS::SNPrint(chars, len, format, prev_cstr, cname, pos, lvl, idx);
+    prev_cstr = chars;
+  }
+  return prev_cstr;
 }
 
 
@@ -13194,7 +13210,7 @@
 
 
 RawUnhandledException* UnhandledException::New(const Instance& exception,
-                                               const Instance& stacktrace,
+                                               const Stacktrace& stacktrace,
                                                Heap::Space space) {
   ASSERT(Object::unhandled_exception_class() != Class::null());
   UnhandledException& result = UnhandledException::Handle();
@@ -13222,7 +13238,7 @@
     result ^= raw;
   }
   result.set_exception(Object::null_instance());
-  result.set_stacktrace(Object::null_instance());
+  result.set_stacktrace(Stacktrace::Handle());
   return result.raw();
 }
 
@@ -13232,7 +13248,7 @@
 }
 
 
-void UnhandledException::set_stacktrace(const Instance& stacktrace) const {
+void UnhandledException::set_stacktrace(const Stacktrace& stacktrace) const {
   StorePointer(&raw_ptr()->stacktrace_, stacktrace.raw());
 }
 
@@ -20099,6 +20115,7 @@
                                    intptr_t frame_index) {
   const char* kFormatWithCol = "#%-6d %s (%s:%d:%d)\n";
   const char* kFormatNoCol = "#%-6d %s (%s:%d)\n";
+  const char* kFormatNoLine = "#%-6d %s (%s)\n";
   const intptr_t token_pos = code.GetTokenIndexOfPC(pc);
   const Script& script = Script::Handle(isolate, function.script());
   const String& function_name =
@@ -20106,7 +20123,7 @@
   const String& url = String::Handle(isolate, script.url());
   intptr_t line = -1;
   intptr_t column = -1;
-  if (token_pos >= 0) {
+  if (token_pos > 0) {
     if (script.HasSource()) {
       script.GetTokenLocation(token_pos, &line, &column);
     } else {
@@ -20124,7 +20141,7 @@
                 frame_index,
                 function_name.ToCString(),
                 url.ToCString(), line, column);
-  } else {
+  } else if (line >= 0) {
     len = OS::SNPrint(NULL, 0, kFormatNoCol,
                       frame_index, function_name.ToCString(),
                       url.ToCString(), line);
@@ -20132,6 +20149,14 @@
     OS::SNPrint(chars, (len + 1), kFormatNoCol,
                 frame_index, function_name.ToCString(),
                 url.ToCString(), line);
+  } else {
+    len = OS::SNPrint(NULL, 0, kFormatNoLine,
+                      frame_index, function_name.ToCString(),
+                      url.ToCString());
+    chars = isolate->current_zone()->Alloc<char>(len + 1);
+    OS::SNPrint(chars, (len + 1), kFormatNoLine,
+                frame_index, function_name.ToCString(),
+                url.ToCString());
   }
   frame_strings->Add(chars);
   return len;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c57f824..47d6afd 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2152,6 +2152,28 @@
     return modifier() == RawFunction::kAsync;
   }
 
+  bool IsAsyncClosure() const {
+    return is_generated_body() &&
+        Function::Handle(parent_function()).IsAsyncFunction();
+  }
+
+  bool IsGenerator() const {
+    return (modifier() & RawFunction::kGeneratorBit) != 0;
+  }
+
+  bool IsSyncGenerator() const {
+    return modifier() == RawFunction::kSyncGen;
+  }
+
+  bool IsSyncGenClosure() const {
+    return is_generated_body() &&
+        Function::Handle(parent_function()).IsSyncGenerator();
+  }
+
+  bool IsAsyncOrGenerator() const {
+    return modifier() != RawFunction::kNoModifier;
+  }
+
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawFunction));
   }
@@ -2239,7 +2261,7 @@
   V(External, is_external)                                                     \
   V(AllowsHoistingCheckClass, allows_hoisting_check_class)                     \
   V(AllowsBoundsCheckGeneralization, allows_bounds_check_generalization)       \
-  V(AsyncClosure, is_async_closure)                                            \
+  V(GeneratedBody, is_generated_body)                                          \
   V(AlwaysInline, always_inline)                                               \
   V(PolymorphicTarget, is_polymorphic_target)                                  \
 
@@ -2262,6 +2284,8 @@
     kRecognizedTagPos = kKindTagPos + kKindTagSize,
     kRecognizedTagSize = 8,
     kModifierPos = kRecognizedTagPos + kRecognizedTagSize,
+    kModifierSize = 2,
+    kLastModifierBitPos = kModifierPos + (kModifierSize - 1),
     // Single bit sized fields start here.
 #define DECLARE_BIT(name, _) k##name##Bit,
 FOR_EACH_FUNCTION_KIND_BIT(DECLARE_BIT)
@@ -2277,11 +2301,14 @@
 
   class KindBits :
     public BitField<RawFunction::Kind, kKindTagPos, kKindTagSize> {};  // NOLINT
+
   class RecognizedBits : public BitField<MethodRecognizer::Kind,
                                          kRecognizedTagPos,
                                          kRecognizedTagSize> {};
   class ModifierBits :
-      public BitField<RawFunction::AsyncModifier, kModifierPos, 1> {};  // NOLINT
+    public BitField<RawFunction::AsyncModifier,
+                   kModifierPos,
+                   kModifierSize> {};  // NOLINT
 
 #define DEFINE_BIT(name, _) \
   class name##Bit : public BitField<bool, k##name##Bit, 1> {};
@@ -4549,7 +4576,7 @@
     return OFFSET_OF(RawUnhandledException, exception_);
   }
 
-  RawInstance* stacktrace() const { return raw_ptr()->stacktrace_; }
+  RawStacktrace* stacktrace() const { return raw_ptr()->stacktrace_; }
   static intptr_t stacktrace_offset() {
     return OFFSET_OF(RawUnhandledException, stacktrace_);
   }
@@ -4559,7 +4586,7 @@
   }
 
   static RawUnhandledException* New(const Instance& exception,
-                                    const Instance& stacktrace,
+                                    const Stacktrace& stacktrace,
                                     Heap::Space space = Heap::kNew);
 
   virtual const char* ToErrorCString() const;
@@ -4568,7 +4595,7 @@
   static RawUnhandledException* New(Heap::Space space = Heap::kNew);
 
   void set_exception(const Instance& exception) const;
-  void set_stacktrace(const Instance& stacktrace) const;
+  void set_stacktrace(const Stacktrace& stacktrace) const;
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(UnhandledException, Error);
   friend class Class;
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 59ba57a..45759d9 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -150,7 +150,8 @@
   // Allocate pre-allocated unhandled exception object initialized with the
   // pre-allocated OutOfMemoryError.
   const UnhandledException& unhandled_exception = UnhandledException::Handle(
-      UnhandledException::New(Instance::Cast(result), Object::null_instance()));
+      UnhandledException::New(Instance::Cast(result),
+                              Stacktrace::Handle(isolate)));
   set_preallocated_unhandled_exception(unhandled_exception);
 
   const Array& code_array = Array::Handle(
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 17d5367..c9b3345 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -888,8 +888,14 @@
   }
 
   if (!HasReturnNode(node_sequence)) {
-    // Add implicit return node.
-    node_sequence->Add(new ReturnNode(func.end_token_pos()));
+    // Add implicit return node. The implicit return value of synchronous
+    // generator closures is false, to indicate that there are no more
+    // elements in the iterable. In other cases the implicit return value
+    // is null.
+    AstNode* return_value = func.IsSyncGenClosure()
+        ? new LiteralNode(func.end_token_pos(), Bool::False())
+        : new LiteralNode(func.end_token_pos(), Instance::ZoneHandle());
+    node_sequence->Add(new ReturnNode(func.end_token_pos(), return_value));
   }
   if (parsed_function->has_expression_temp_var()) {
     node_sequence->scope()->AddVariable(parsed_function->expression_temp_var());
@@ -3060,38 +3066,19 @@
         &Symbols::TypeArgumentsParameter(),
         &Type::ZoneHandle(Z, Type::DynamicType()));
   }
+  // Expect the parameter list unless this is a getter function, or the
+  // body closure of an async or generator getter function.
   ASSERT((CurrentToken() == Token::kLPAREN) ||
          func.IsGetterFunction() ||
-         func.is_async_closure());
+         (func.is_generated_body() &&
+             Function::Handle(func.parent_function()).IsGetterFunction()));
   const bool allow_explicit_default_values = true;
   if (func.IsGetterFunction()) {
     // Populate function scope with the formal parameters. Since in this case
     // we are compiling a getter this will at most populate the receiver.
     AddFormalParamsToScope(&params, current_block_->scope);
-  } else if (func.is_async_closure()) {
-    // Async closures have two optional parameters:
-    // * A continuation result.
-    // * A continuation error.
-    //
-    // If the error!=null we rethrow the error at the next await.
-    const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
-    ParamDesc result_param;
-    result_param.name = &Symbols::AsyncOperationParam();
-    result_param.default_value = &Object::null_instance();
-    result_param.type = &dynamic_type;
-    ParamDesc error_param;
-    error_param.name = &Symbols::AsyncOperationErrorParam();
-    error_param.default_value = &Object::null_instance();
-    error_param.type = &dynamic_type;
-    ParamDesc stack_trace_param;
-    stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam();
-    stack_trace_param.default_value = &Object::null_instance();
-    stack_trace_param.type = &dynamic_type;
-    params.parameters->Add(result_param);
-    params.parameters->Add(error_param);
-    params.parameters->Add(stack_trace_param);
-    params.num_optional_parameters += 3;
-    params.has_optional_positional_parameters = true;
+  } else if (func.IsAsyncClosure()) {
+    AddAsyncClosureParameters(&params);
     SetupDefaultsForOptionalParams(&params, default_parameter_values);
     AddFormalParamsToScope(&params, current_block_->scope);
     ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
@@ -3099,10 +3086,23 @@
     if (!Function::Handle(func.parent_function()).IsGetterFunction()) {
       // Parse and discard any formal parameters. They are accessed as
       // context variables.
-      ParamList parse_away;
+      ParamList discarded_params;
       ParseFormalParameterList(allow_explicit_default_values,
                                false,
-                               &parse_away);
+                               &discarded_params);
+    }
+  } else if (func.IsSyncGenClosure()) {
+    AddSyncGenClosureParameters(&params);
+    SetupDefaultsForOptionalParams(&params, default_parameter_values);
+    AddFormalParamsToScope(&params, current_block_->scope);
+    ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
+    if (!Function::Handle(func.parent_function()).IsGetterFunction()) {
+      // Parse and discard any formal parameters. They are accessed as
+      // context variables.
+      ParamList discarded_params;
+      ParseFormalParameterList(allow_explicit_default_values,
+                               false,
+                               &discarded_params);
     }
   } else {
     ParseFormalParameterList(allow_explicit_default_values, false, &params);
@@ -3144,24 +3144,38 @@
     }
   }
 
+  const intptr_t modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
-  func.set_modifier(func_modifier);
+  if (!func.is_generated_body()) {
+    // Don't add a modifier to the closure representing the body of
+    // the asynchronous function or generator.
+    func.set_modifier(func_modifier);
+  }
 
   OpenBlock();  // Open a nested scope for the outermost function block.
 
-  Function& async_closure = Function::ZoneHandle(Z);
-  if (func.IsAsyncFunction() && !func.is_async_closure()) {
+  Function& generated_body_closure = Function::ZoneHandle(Z);
+  if (func.IsAsyncFunction()) {
+    ASSERT(!func.is_generated_body());
     // The code of an async function is synthesized. Disable debugging.
     func.set_is_debuggable(false);
-    async_closure = OpenAsyncFunction(func.token_pos());
-  } else if (func.is_async_closure()) {
+    generated_body_closure = OpenAsyncFunction(func.token_pos());
+  } else if (func.IsAsyncClosure()) {
     // The closure containing the body of an async function is debuggable.
     ASSERT(func.is_debuggable());
     OpenAsyncClosure();
+  } else if (func.IsSyncGenerator()) {
+    // The code of a sync generator is synthesized. Disable debugging.
+    func.set_is_debuggable(false);
+    generated_body_closure = OpenSyncGeneratorFunction(func.token_pos());
+  } else if (func.IsSyncGenClosure()) {
+    // The closure containing the body of a sync generator is debuggable.
+    ASSERT(func.is_debuggable());
+    // Nothing special to do.
   }
 
   BoolScope allow_await(&this->await_is_keyword_,
-                        func.IsAsyncFunction() || func.is_async_closure());
+                        func.IsAsyncOrGenerator() || func.is_generated_body());
   intptr_t end_token_pos = 0;
   if (CurrentToken() == Token::kLBRACE) {
     ConsumeToken();
@@ -3175,6 +3189,10 @@
     end_token_pos = TokenPos();
     ExpectToken(Token::kRBRACE);
   } else if (CurrentToken() == Token::kARROW) {
+    if (func.IsGenerator()) {
+      ReportError(modifier_pos,
+                  "=> style function may not be sync* or async* generator");
+    }
     ConsumeToken();
     if (String::Handle(Z, func.name()).Equals(
         Symbols::EqualOperator())) {
@@ -3221,11 +3239,16 @@
          func.end_token_pos() == end_token_pos);
   func.set_end_token_pos(end_token_pos);
   SequenceNode* body = CloseBlock();
-  if (func.IsAsyncFunction() && !func.is_async_closure()) {
-    body = CloseAsyncFunction(async_closure, body);
-    async_closure.set_end_token_pos(end_token_pos);
-  } else if (func.is_async_closure()) {
+  if (func.IsAsyncFunction()) {
+    body = CloseAsyncFunction(generated_body_closure, body);
+    generated_body_closure.set_end_token_pos(end_token_pos);
+  } else if (func.IsAsyncClosure()) {
     body = CloseAsyncClosure(body);
+  } else if (func.IsSyncGenerator()) {
+    body = CloseSyncGenFunction(generated_body_closure, body);
+    generated_body_closure.set_end_token_pos(end_token_pos);
+  } else if (func.IsSyncGenClosure()) {
+    body->scope()->RecursivelyCaptureAllVariables();
   }
   current_block_->statements->Add(body);
   innermost_function_ = saved_innermost_function.raw();
@@ -3544,11 +3567,12 @@
                 method->name->ToCString());
   }
 
+  const intptr_t modifier_pos = TokenPos();
   RawFunction::AsyncModifier async_modifier = ParseFunctionModifier();
   if ((method->IsFactoryOrConstructor() || method->IsSetter()) &&
-      async_modifier != RawFunction::kNoModifier) {
-    ReportError(method->name_pos,
-                "%s '%s' may not be async",
+      (async_modifier != RawFunction::kNoModifier)) {
+    ReportError(modifier_pos,
+                "%s '%s' may not be async, async* or sync*",
                 (method->IsSetter()) ? "setter" : "constructor",
                 method->name->ToCString());
   }
@@ -3583,6 +3607,11 @@
       method_end_pos = TokenPos();
       ExpectToken(Token::kRBRACE);
     } else {
+      if ((async_modifier & RawFunction::kGeneratorBit) != 0) {
+        ReportError(modifier_pos,
+                    "=> style function may not be sync* or async* generator");
+      }
+
       ConsumeToken();
       BoolScope allow_await(&this->await_is_keyword_,
                             async_modifier != RawFunction::kNoModifier);
@@ -3646,6 +3675,12 @@
     }
   }
 
+  if (method->has_abstract && (async_modifier != RawFunction::kNoModifier)) {
+    ReportError(modifier_pos,
+                "abstract function '%s' may not be async, async* or sync*",
+                method->name->ToCString());
+  }
+
   RawFunction::Kind function_kind;
   if (method->IsFactoryOrConstructor()) {
     function_kind = RawFunction::kConstructor;
@@ -5195,7 +5230,22 @@
 RawFunction::AsyncModifier Parser::ParseFunctionModifier() {
   if (CurrentLiteral()->raw() == Symbols::Async().raw()) {
     ConsumeToken();
-    return RawFunction::kAsync;
+    if (CurrentToken() == Token::kMUL) {
+      ReportError("async* generator functions are not yet supported");
+      ConsumeToken();
+      return RawFunction::kAsyncGen;
+    } else {
+      return RawFunction::kAsync;
+    }
+  } else if ((CurrentLiteral()->raw() == Symbols::Sync().raw()) &&
+      (LookaheadToken(1) == Token::kMUL)) {
+    const bool enableSyncStar = true;
+    if (!enableSyncStar) {
+      ReportError("sync* generator functions are not yet supported");
+    }
+    ConsumeToken();
+    ConsumeToken();
+    return RawFunction::kSyncGen;
   }
   return RawFunction::kNoModifier;
 }
@@ -5254,6 +5304,7 @@
   const bool allow_explicit_default_values = true;
   ParseFormalParameterList(allow_explicit_default_values, false, &params);
 
+  const intptr_t modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
 
   intptr_t function_end_pos = function_pos;
@@ -5266,6 +5317,10 @@
     function_end_pos = TokenPos();
     ExpectToken(Token::kRBRACE);
   } else if (CurrentToken() == Token::kARROW) {
+    if ((func_modifier & RawFunction::kGeneratorBit) != 0) {
+      ReportError(modifier_pos,
+                  "=> style function may not be sync* or async* generator");
+    }
     ConsumeToken();
     BoolScope allow_await(&this->await_is_keyword_,
                           func_modifier != RawFunction::kNoModifier);
@@ -5395,7 +5450,12 @@
                 field_name->ToCString());
   }
 
+  const intptr_t modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
+  if (!is_getter && (func_modifier != RawFunction::kNoModifier)) {
+    ReportError(modifier_pos,
+                "setter function cannot be async, async* or sync*");
+  }
 
   intptr_t accessor_end_pos = accessor_pos;
   bool is_native = false;
@@ -5915,7 +5975,7 @@
   }
 
   ASSERT(try_blocks_list_ != NULL);
-  if (innermost_function().is_async_closure() ||
+  if (innermost_function().IsAsyncClosure() ||
       innermost_function().IsAsyncFunction()) {
     if ((try_blocks_list_->outer_try_block() != NULL) &&
         (try_blocks_list_->outer_try_block()->try_block()
@@ -5945,7 +6005,7 @@
   completer_args->Add(
       new (Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_param.var));
   current_block_->statements->Add(new (Z) InstanceCallNode(
-      Scanner::kNoSourcePos,
+      TokenPos(),
       new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_completer),
       Symbols::CompleterCompleteError(),
       completer_args));
@@ -6020,15 +6080,175 @@
   OpenBlock();
   PushTryBlock(current_block_);
 
-  if (innermost_function().is_async_closure() ||
+  if (innermost_function().IsAsyncClosure() ||
       innermost_function().IsAsyncFunction()) {
     SetupSavedTryContext(context_var);
   }
 }
 
 
+void Parser::AddSyncGenClosureParameters(ParamList* params) {
+  // Create the parameter list for the body closure of a sync generator:
+  // 1) Implicit closure parameter;
+  // 2) Iterator
+  const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
+  // Add implicit closure parameter if not already present.
+  if (params->parameters->length() == 0) {
+    params->AddFinalParameter(0, &Symbols::ClosureParameter(), &dynamic_type);
+  }
+  ParamDesc iterator_param;
+  iterator_param.name = &Symbols::IteratorParameter();
+  iterator_param.type = &dynamic_type;
+  params->parameters->Add(iterator_param);
+  params->num_fixed_parameters++;
+}
+
+
+RawFunction* Parser::OpenSyncGeneratorFunction(intptr_t func_pos) {
+  Function& body = Function::Handle(Z);
+  String& body_closure_name = String::Handle(Z);
+  bool is_new_closure = false;
+
+  AddContinuationVariables();
+
+  // Check whether a function for the body of this generator
+  // function has already been created by a previous
+  // compilation.
+  const Function& found_func = Function::Handle(
+      Z, current_class().LookupClosureFunction(func_pos));
+  if (!found_func.IsNull() &&
+      (found_func.token_pos() == func_pos) &&
+      (found_func.script() == innermost_function().script()) &&
+      (found_func.parent_function() == innermost_function().raw())) {
+    ASSERT(found_func.IsSyncGenClosure());
+    body = found_func.raw();
+    body_closure_name = body.name();
+  } else {
+    // Create the closure containing the body of this generator function.
+    String& generator_name = String::Handle(Z, innermost_function().name());
+    body_closure_name =
+        String::NewFormatted("<%s_sync_body>", generator_name.ToCString());
+    body_closure_name = Symbols::New(body_closure_name);
+    body = Function::NewClosureFunction(body_closure_name,
+                                        innermost_function(),
+                                        func_pos);
+    body.set_is_generated_body(true);
+    body.set_result_type(AbstractType::Handle(Type::DynamicType()));
+    is_new_closure = true;
+  }
+
+  ParamList closure_params;
+  AddSyncGenClosureParameters(&closure_params);
+
+  if (is_new_closure) {
+    // Add the parameters to the newly created closure.
+    AddFormalParamsToFunction(&closure_params, body);
+
+    // Create and set the signature class of the closure.
+    const String& sig = String::Handle(Z, body.Signature());
+    Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
+    if (sig_cls.IsNull()) {
+      sig_cls = Class::NewSignatureClass(sig, body, script_, body.token_pos());
+      library_.AddClass(sig_cls);
+    }
+    body.set_signature_class(sig_cls);
+    const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
+    if (!sig_type.IsFinalized()) {
+      ClassFinalizer::FinalizeType(
+          sig_cls, sig_type, ClassFinalizer::kCanonicalize);
+    }
+    ASSERT(AbstractType::Handle(Z, body.result_type()).IsResolved());
+    ASSERT(body.NumParameters() == closure_params.parameters->length());
+  }
+
+  OpenFunctionBlock(body);
+  AddFormalParamsToScope(&closure_params, current_block_->scope);
+  OpenBlock();
+
+  /*
+  async_temp_scope_ = current_block_->scope; // Is this needed?
+  */
+  return body.raw();
+}
+
+SequenceNode* Parser::CloseSyncGenFunction(const Function& closure,
+                                           SequenceNode* closure_body) {
+  // The block for the closure body has already been closed. Close the
+  // corresponding function block.
+  CloseBlock();
+
+  closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
+  closure_body->scope()->LookupVariable(Symbols::AwaitContextVar(), false);
+
+  // :await_jump_var = -1;
+  LocalVariable* jump_var =
+      current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
+  LiteralNode* init_value =
+      new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+  current_block_->statements->Add(
+      new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+
+  // return new SyncIterable(body_closure);
+  const Class& iterable_class =
+      Class::Handle(Z, Library::LookupCoreClass(Symbols::_SyncIterable()));
+  ASSERT(!iterable_class.IsNull());
+  const Function& iterable_constructor = Function::ZoneHandle(Z,
+      iterable_class.LookupConstructorAllowPrivate(
+          Symbols::_SyncIterableConstructor()));
+  ASSERT(!iterable_constructor.IsNull());
+
+  const String& closure_name = String::Handle(Z, closure.name());
+  ASSERT(closure_name.IsSymbol());
+
+  ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+  ClosureNode* closure_obj = new(Z) ClosureNode(
+      Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
+  arguments->Add(closure_obj);
+  ConstructorCallNode* new_iterable =
+      new(Z) ConstructorCallNode(Scanner::kNoSourcePos,
+          TypeArguments::ZoneHandle(Z),
+          iterable_constructor,
+          arguments);
+  ReturnNode* return_node =
+      new (Z) ReturnNode(Scanner::kNoSourcePos, new_iterable);
+  current_block_->statements->Add(return_node);
+  return CloseBlock();
+}
+
+
+void Parser::AddAsyncClosureParameters(ParamList* params) {
+  // Async closures have two optional parameters:
+  // * A continuation result.
+  // * A continuation error.
+  // * A continuation stack trace.
+  const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
+  // Add implicit closure parameter if not yet present.
+  if (params->parameters->length() == 0) {
+    params->AddFinalParameter(0, &Symbols::ClosureParameter(), &dynamic_type);
+  }
+  ParamDesc result_param;
+  result_param.name = &Symbols::AsyncOperationParam();
+  result_param.default_value = &Object::null_instance();
+  result_param.type = &dynamic_type;
+  params->parameters->Add(result_param);
+  ParamDesc error_param;
+  error_param.name = &Symbols::AsyncOperationErrorParam();
+  error_param.default_value = &Object::null_instance();
+  error_param.type = &dynamic_type;
+  params->parameters->Add(error_param);
+  ParamDesc stack_trace_param;
+  stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam();
+  stack_trace_param.default_value = &Object::null_instance();
+  stack_trace_param.type = &dynamic_type;
+  params->parameters->Add(stack_trace_param);
+  params->has_optional_positional_parameters = true;
+  params->num_optional_parameters += 3;
+}
+
+
 RawFunction* Parser::OpenAsyncFunction(intptr_t async_func_pos) {
   TRACE_PARSER("OpenAsyncFunction");
+  AddContinuationVariables();
   AddAsyncClosureVariables();
   Function& closure = Function::Handle(Z);
   bool is_new_closure = false;
@@ -6042,7 +6262,7 @@
       (found_func.token_pos() == async_func_pos) &&
       (found_func.script() == innermost_function().script()) &&
       (found_func.parent_function() == innermost_function().raw())) {
-    ASSERT(found_func.is_async_closure());
+    ASSERT(found_func.IsAsyncClosure());
     closure = found_func.raw();
   } else {
     // Create the closure containing the body of this async function.
@@ -6054,33 +6274,13 @@
         String::Handle(Z, Symbols::New(closure_name)),
         innermost_function(),
         async_func_pos);
-    closure.set_is_async_closure(true);
+    closure.set_is_generated_body(true);
     closure.set_result_type(AbstractType::Handle(Type::DynamicType()));
     is_new_closure = true;
   }
   // Create the parameter list for the async body closure.
   ParamList closure_params;
-  const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
-  closure_params.AddFinalParameter(
-      async_func_pos, &Symbols::ClosureParameter(), &dynamic_type);
-  ParamDesc result_param;
-  result_param.name = &Symbols::AsyncOperationParam();
-  result_param.default_value = &Object::null_instance();
-  result_param.type = &dynamic_type;
-  closure_params.parameters->Add(result_param);
-  ParamDesc error_param;
-  error_param.name = &Symbols::AsyncOperationErrorParam();
-  error_param.default_value = &Object::null_instance();
-  error_param.type = &dynamic_type;
-  closure_params.parameters->Add(error_param);
-  ParamDesc stack_trace_param;
-  stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam();
-  stack_trace_param.default_value = &Object::null_instance();
-  stack_trace_param.type = &dynamic_type;
-  closure_params.parameters->Add(stack_trace_param);
-  closure_params.has_optional_positional_parameters = true;
-  closure_params.num_optional_parameters += 3;
-
+  AddAsyncClosureParameters(&closure_params);
   if (is_new_closure) {
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, closure);
@@ -6110,12 +6310,10 @@
 }
 
 
-void Parser::AddAsyncClosureVariables() {
-  // Add to AST:
+void Parser::AddContinuationVariables() {
+  // Add to current block's scope:
   //   var :await_jump_var;
   //   var :await_ctx_var;
-  //   var :async_op;
-  //   var :async_completer;
   const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
   LocalVariable* await_jump_var = new (Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), dynamic_type);
@@ -6127,12 +6325,20 @@
   current_block_->scope->AddVariable(await_ctx_var);
   current_block_->scope->CaptureVariable(Symbols::AwaitContextVar());
   await_ctx_var->set_is_captured();
-  LocalVariable* async_op_var = new (Z) LocalVariable(
+}
+
+
+void Parser::AddAsyncClosureVariables() {
+  // Add to current block's scope:
+  //   var :async_op;
+  //   var :async_completer;
+  const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
+  LocalVariable* async_op_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type);
   current_block_->scope->AddVariable(async_op_var);
   current_block_->scope->CaptureVariable(Symbols::AsyncOperation());
   async_op_var->set_is_captured();
-  LocalVariable* async_completer = new (Z) LocalVariable(
+  LocalVariable* async_completer = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncCompleter(), dynamic_type);
   current_block_->scope->AddVariable(async_completer);
   current_block_->scope->CaptureVariable(Symbols::AsyncCompleter());
@@ -6214,12 +6420,12 @@
   current_block_->statements->Add(store_completer);
 
   // :await_jump_var = -1;
-  LocalVariable* jump_var = current_block_->scope->LookupVariable(
-        Symbols::AwaitJumpVar(), false);
+  LocalVariable* jump_var =
+      current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
   LiteralNode* init_value =
-    new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+      new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
   current_block_->statements->Add(
-      new (Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+      new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
 
   // Add to AST:
   //   :async_op = <closure>;  (containing the original body)
@@ -6234,7 +6440,7 @@
   current_block_->statements->Add(store_async_op);
 
   // Add to AST:
-  //   new Future(:async_op);
+  //   new Future.microtask(:async_op);
   ArgumentListNode* arguments = new (Z) ArgumentListNode(Scanner::kNoSourcePos);
   arguments->Add(new (Z) LoadLocalNode(
       Scanner::kNoSourcePos, async_op_var));
@@ -6476,8 +6682,7 @@
                 "missing initialization of 'final' or 'const' variable");
   } else {
     // Initialize variable with null.
-    AstNode* null_expr = new(Z) LiteralNode(
-        ident_pos, Instance::ZoneHandle(Z));
+    AstNode* null_expr = new(Z) LiteralNode(ident_pos, Instance::ZoneHandle(Z));
     initialization = new(Z) StoreLocalNode(
         ident_pos, variable, null_expr);
   }
@@ -6907,7 +7112,11 @@
 
 // Returns true if the current token is kIDENT or a pseudo-keyword.
 bool Parser::IsIdentifier() {
-  return Token::IsIdentifier(CurrentToken()) && !IsAwaitKeyword();
+  return Token::IsIdentifier(CurrentToken()) &&
+      !(await_is_keyword_ &&
+       ((CurrentLiteral()->raw() == Symbols::Await().raw()) ||
+       (CurrentLiteral()->raw() == Symbols::Async().raw()) ||
+       (CurrentLiteral()->raw() == Symbols::YieldKw().raw())));
 }
 
 
@@ -7056,7 +7265,8 @@
         (CurrentToken() == Token::kARROW) ||
         (is_top_level_ && IsLiteral("native")) ||
         is_external ||
-        (CurrentLiteral()->raw() == Symbols::Async().raw())) {
+        (CurrentLiteral()->raw() == Symbols::Async().raw()) ||
+        (CurrentLiteral()->raw() == Symbols::Sync().raw())) {
       SetPosition(saved_pos);
       return true;
     }
@@ -7546,6 +7756,12 @@
   ConsumeToken();  // for.
   ExpectToken(Token::kLPAREN);
 
+  if (!innermost_function().IsAsyncFunction() &&
+      !innermost_function().IsAsyncClosure()) {
+    ReportError(await_for_pos,
+                "await for loop is only allowed in async function");
+  }
+
   // Parse loop variable.
   bool loop_var_is_final = (CurrentToken() == Token::kFINAL);
   if (CurrentToken() == Token::kCONST) {
@@ -7728,7 +7944,7 @@
   // Generate initialization of iterator variable.
   ArgumentListNode* no_args = new(Z) ArgumentListNode(collection_pos);
   AstNode* get_iterator = new(Z) InstanceGetterNode(
-      collection_pos, collection_expr, Symbols::GetIterator());
+      collection_pos, collection_expr, Symbols::Iterator());
   AstNode* iterator_init =
       new(Z) StoreLocalNode(collection_pos, iterator_var, get_iterator);
   current_block_->statements->Add(iterator_init);
@@ -7979,7 +8195,7 @@
   // In case of async closures we need to restore the saved try index of an
   // outer try block (if it exists).  The current try block has already been
   // removed from the stack of try blocks.
-  if ((innermost_function().is_async_closure() ||
+  if ((innermost_function().IsAsyncClosure() ||
        innermost_function().IsAsyncFunction()) &&
       (try_blocks_list_ != NULL)) {
     // We need two unchain two scopes: finally clause, and the try block level.
@@ -8139,7 +8355,7 @@
     // In case of async closures we need to restore the saved try index of an
     // outer try block (if it exists).
     ASSERT(try_blocks_list_ != NULL);
-    if (innermost_function().is_async_closure() ||
+    if (innermost_function().IsAsyncClosure() ||
         innermost_function().IsAsyncFunction()) {
       if ((try_blocks_list_->outer_try_block() != NULL) &&
           (try_blocks_list_->outer_try_block()->try_block()
@@ -8247,7 +8463,7 @@
     // In case of async closures we need to restore the saved try index of an
     // outer try block (if it exists).
     ASSERT(try_blocks_list_ != NULL);
-    if (innermost_function().is_async_closure() ||
+    if (innermost_function().IsAsyncClosure() ||
         innermost_function().IsAsyncFunction()) {
       if ((try_blocks_list_->outer_try_block() != NULL) &&
           (try_blocks_list_->outer_try_block()->try_block()
@@ -8285,15 +8501,17 @@
       async_saved_try_ctx_name, false);
   ASSERT(async_saved_try_ctx != NULL);
   ASSERT(saved_try_context != NULL);
-  current_block_->statements->Add(new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos, async_saved_try_ctx, new (Z) LoadLocalNode(
-          Scanner::kNoSourcePos, saved_try_context)));
+  current_block_->statements->Add(new(Z) StoreLocalNode(
+      Scanner::kNoSourcePos,
+      async_saved_try_ctx,
+      new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context)));
   parsed_function()->set_saved_try_ctx(saved_try_context);
   parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name);
 }
 
 
-// Set up the currently relevant :saved_try_context_var on the stack:
+// Restore the currently relevant :saved_try_context_var on the stack
+// from the captured :async_saved_try_cts_var.
 // * Try blocks: Set the context variable for this try block.
 // * Catch/finally blocks: Set the context variable for any outer try block (if
 //   existent).
@@ -8381,7 +8599,7 @@
   PushTryBlock(current_block_);
   ExpectToken(Token::kLBRACE);
 
-  if (innermost_function().is_async_closure() ||
+  if (innermost_function().IsAsyncClosure() ||
       innermost_function().IsAsyncFunction()) {
     SetupSavedTryContext(context_var);
   }
@@ -8560,18 +8778,72 @@
     const intptr_t return_pos = TokenPos();
     ConsumeToken();
     if (CurrentToken() != Token::kSEMICOLON) {
+      const intptr_t expr_pos = TokenPos();
       if (current_function().IsConstructor() &&
           (current_block_->scope->function_level() == 0)) {
-        ReportError(return_pos,
-                    "return of a value not allowed in constructors");
+        ReportError(expr_pos,
+                    "return of a value is not allowed in constructors");
+      } else if (current_function().IsGenerator()) {
+        ReportError(expr_pos, "generator functions may not return a value");
       }
       AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
       statement = new(Z) ReturnNode(statement_pos, expr);
     } else {
-      statement = new(Z) ReturnNode(statement_pos);
+      if (current_function().IsSyncGenClosure() &&
+          (current_block_->scope->function_level() == 0)) {
+        // In a synchronous generator, return without an expression
+        // returns false, signaling that the iterator terminates and
+        // did not yield a value.
+        statement = new(Z) ReturnNode(statement_pos,
+            new(Z) LiteralNode(return_pos, Bool::False()));
+      } else {
+        statement = new(Z) ReturnNode(statement_pos);
+      }
     }
     AddNodeForFinallyInlining(statement);
     ExpectSemicolon();
+  } else if (IsYieldKeyword()) {
+    bool is_yield_each = false;
+    ConsumeToken();
+    ASSERT(innermost_function().IsGenerator() ||
+           innermost_function().IsSyncGenClosure());
+    if (CurrentToken() == Token::kMUL) {
+      is_yield_each = true;
+      ConsumeToken();
+    }
+    AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
+    LocalVariable* iterator_param =
+        LookupLocalScope(Symbols::IteratorParameter());
+    ASSERT(iterator_param != NULL);
+    // Generate :iterator.current = expr;
+    AstNode* iterator =
+        new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_param);
+    AstNode* store_current =
+        new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+                                  iterator,
+                                  String::ZoneHandle(Symbols::Current().raw()),
+                                  expr);
+    LetNode* yield = new(Z) LetNode(statement_pos);
+    yield->AddNode(store_current);
+    if (is_yield_each) {
+      // Generate :iterator.isYieldEach = true;
+      AstNode* set_is_yield_each =
+          new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+              iterator,
+              String::ZoneHandle(Symbols::IsYieldEach().raw()),
+              new(Z) LiteralNode(TokenPos(), Bool::True()));
+      yield->AddNode(set_is_yield_each);
+    }
+    AwaitMarkerNode* await_marker = new(Z) AwaitMarkerNode();
+    await_marker->set_scope(current_block_->scope);
+    yield->AddNode(await_marker);
+    // Return true to indicate that a value has been generated.
+    ReturnNode* return_true = new(Z) ReturnNode(statement_pos,
+        new(Z) LiteralNode(TokenPos(), Bool::True()));
+    return_true->set_return_type(ReturnNode::kContinuationTarget);
+    yield->AddNode(return_true);
+    statement = yield;
+    ExpectSemicolon();
   } else if (token == Token::kIF) {
     statement = ParseIfStatement(label_name);
   } else if (token == Token::kASSERT) {
@@ -8757,6 +9029,12 @@
 }
 
 
+bool Parser::IsYieldKeyword() {
+  return await_is_keyword_ &&
+         (CurrentLiteral()->raw() == Symbols::YieldKw().raw());
+}
+
+
 static bool IsIncrementOperator(Token::Kind token) {
   return token == Token::kINCR || token == Token::kDECR;
 }
@@ -9414,9 +9692,13 @@
   const intptr_t op_pos = TokenPos();
   if (IsAwaitKeyword()) {
     TRACE_PARSER("ParseAwaitExpr");
+    if (!innermost_function().IsAsyncFunction() &&
+        !innermost_function().IsAsyncClosure()) {
+      ReportError("await operator is only allowed in async function");
+    }
     ConsumeToken();
     parsed_function()->record_await();
-    expr = new (Z) AwaitNode(TokenPos(), ParseUnaryExpr());
+    expr = new (Z) AwaitNode(op_pos, ParseUnaryExpr());
   } else if (IsPrefixOperator(CurrentToken())) {
     Token::Kind unary_op = CurrentToken();
     if (unary_op == Token::kSUB) {
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 7af16e6..326906d 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -345,6 +345,7 @@
   String* ExpectIdentifier(const char* msg);
   bool IsLiteral(const char* literal);
   bool IsAwaitKeyword();
+  bool IsYieldKeyword();
 
   void SkipIf(Token::Kind);
   void SkipBlock();
@@ -558,12 +559,18 @@
   void OpenFunctionBlock(const Function& func);
   void OpenAsyncClosure();
   RawFunction* OpenAsyncFunction(intptr_t formal_param_pos);
+  RawFunction* OpenSyncGeneratorFunction(intptr_t func_pos);
+  SequenceNode* CloseSyncGenFunction(const Function& closure,
+                                     SequenceNode* closure_node);
+  void AddSyncGenClosureParameters(ParamList* params);
   void OpenAsyncTryBlock();
   SequenceNode* CloseBlock();
   SequenceNode* CloseAsyncFunction(const Function& closure,
                                    SequenceNode* closure_node);
   SequenceNode* CloseAsyncClosure(SequenceNode* body);
   SequenceNode* CloseAsyncTryBlock(SequenceNode* try_block);
+  void AddAsyncClosureParameters(ParamList* params);
+  void AddContinuationVariables();
   void AddAsyncClosureVariables();
 
 
@@ -786,8 +793,9 @@
   // global variables.
   bool is_top_level_;
 
-  // await_is_keyword_ is true if we are parsing an async function. In this
-  // context async is not treated as identifier but as a keyword.
+  // await_is_keyword_ is true if we are parsing an async or generator
+  // function. In this context the identifiers await, async and yield
+  // are treated as keywords.
   bool await_is_keyword_;
 
   // The member currently being parsed during "top level" parsing.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 749ee45..5f13b40 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -521,6 +521,8 @@
   void InitializeSmi(RawSmi* const* addr, RawSmi* value) {
     // Can't use Contains, as array length is initialized through this method.
     ASSERT(reinterpret_cast<uword>(addr) >= RawObject::ToAddr(this));
+    // This is an initializing store, so any previous content is OK.
+    VerifiedMemory::Accept(reinterpret_cast<uword>(addr), kWordSize);
     VerifiedMemory::Write(const_cast<RawSmi**>(addr), value);
   }
 
@@ -699,8 +701,12 @@
   };
 
   enum AsyncModifier {
-    kNoModifier,
-    kAsync,
+    kNoModifier = 0x0,
+    kAsyncBit   = 0x1,
+    kGeneratorBit =  0x2,
+    kAsync      = kAsyncBit,
+    kSyncGen    = kGeneratorBit,
+    kAsyncGen   = kAsyncBit | kGeneratorBit,
   };
 
  private:
@@ -1380,7 +1386,7 @@
     return reinterpret_cast<RawObject**>(&ptr()->exception_);
   }
   RawInstance* exception_;
-  RawInstance* stacktrace_;
+  RawStacktrace* stacktrace_;
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->stacktrace_);
   }
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 25330c4..0361262 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -819,12 +819,11 @@
 typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream);
 
 struct IsolateMessageHandlerEntry {
-  const char* command;
+  const char* method;
   IsolateMessageHandler handler;
 };
 
-static IsolateMessageHandler FindIsolateMessageHandler(const char* command);
-static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command);
+static IsolateMessageHandler FindIsolateMessageHandler(const char* method);
 
 
 // A handler for a root (vm-global) request.
@@ -836,32 +835,26 @@
 typedef bool (*RootMessageHandler)(JSONStream* stream);
 
 struct RootMessageHandlerEntry {
-  const char* command;
+  const char* method;
   RootMessageHandler handler;
 };
 
-static RootMessageHandler FindRootMessageHandler(const char* command);
-static RootMessageHandler FindRootMessageHandlerNew(const char* command);
+static RootMessageHandler FindRootMessageHandler(const char* method);
 
 
-static void PrintArgumentsAndOptions(const JSONObject& obj, JSONStream* js) {
+static void PrintRequest(const JSONObject& obj, JSONStream* js) {
   JSONObject jsobj(&obj, "request");
+  jsobj.AddProperty("method", js->method());
   {
-    JSONArray jsarr(&jsobj, "arguments");
-    for (intptr_t i = 0; i < js->num_arguments(); i++) {
-      jsarr.AddValue(js->GetArgument(i));
+    JSONArray jsarr(&jsobj, "param_keys");
+    for (intptr_t i = 0; i < js->num_params(); i++) {
+      jsarr.AddValue(js->GetParamKey(i));
     }
   }
   {
-    JSONArray jsarr(&jsobj, "option_keys");
-    for (intptr_t i = 0; i < js->num_options(); i++) {
-      jsarr.AddValue(js->GetOptionKey(i));
-    }
-  }
-  {
-    JSONArray jsarr(&jsobj, "option_values");
-    for (intptr_t i = 0; i < js->num_options(); i++) {
-      jsarr.AddValue(js->GetOptionValue(i));
+    JSONArray jsarr(&jsobj, "param_values");
+    for (intptr_t i = 0; i < js->num_params(); i++) {
+      jsarr.AddValue(js->GetParamValue(i));
     }
   }
 }
@@ -885,7 +878,21 @@
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "Error");
   jsobj.AddProperty("message", buffer);
-  PrintArgumentsAndOptions(jsobj, js);
+  PrintRequest(jsobj, js);
+}
+
+
+static void PrintMissingParamError(JSONStream* js,
+                                   const char* param) {
+  PrintError(js, "%s expects the '%s' parameter",
+             js->method(), param);
+}
+
+
+static void PrintInvalidParamError(JSONStream* js,
+                                   const char* param) {
+  PrintError(js, "%s: invalid '%s' parameter: %s",
+             js->method(), param, js->LookupParam(param));
 }
 
 
@@ -910,13 +917,14 @@
   jsobj.AddProperty("id", "");
   jsobj.AddProperty("kind", kind);
   jsobj.AddProperty("message", buffer);
-  PrintArgumentsAndOptions(jsobj, js);
+  PrintRequest(jsobj, js);
 }
 
 
-void Service::HandleIsolateMessageNew(Isolate* isolate, const Array& msg) {
+void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
   ASSERT(isolate != NULL);
   ASSERT(!msg.IsNull());
+  ASSERT(msg.Length() == 5);
 
   {
     StackZone zone(isolate);
@@ -941,11 +949,11 @@
     }
 
     IsolateMessageHandler handler =
-        FindIsolateMessageHandlerNew(method.ToCString());
+        FindIsolateMessageHandler(method.ToCString());
     {
       JSONStream js;
-      js.SetupNew(zone.GetZone(), SendPort::Cast(reply_port).Id(),
-                  method, param_keys, param_values);
+      js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
+               method, param_keys, param_values);
       if (handler == NULL) {
         // Check for an embedder handler.
         EmbedderServiceHandler* e_handler =
@@ -953,8 +961,8 @@
         if (e_handler != NULL) {
           EmbedderHandleMessage(e_handler, &js);
         } else {
-          if (FindRootMessageHandlerNew(method.ToCString()) != NULL) {
-            PrintError(&js, "%s expects no 'isolate' parameter\n",
+          if (FindRootMessageHandler(method.ToCString()) != NULL) {
+            PrintError(&js, "%s does not expect the 'isolateId' parameter",
                        method.ToCString());
           } else {
             PrintError(&js, "Unrecognized method: %s", method.ToCString());
@@ -973,79 +981,6 @@
 }
 
 
-void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
-  ASSERT(isolate != NULL);
-  ASSERT(!msg.IsNull());
-
-  {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
-
-    // Message is a list with five entries.
-    ASSERT(msg.Length() == 5);
-
-    Object& tmp = Object::Handle(isolate);
-    tmp = msg.At(2);
-    if (tmp.IsString()) {
-      return Service::HandleIsolateMessageNew(isolate, msg);
-    }
-
-    Instance& reply_port = Instance::Handle(isolate);
-    GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
-    Array& option_keys = Array::Handle(isolate);
-    Array& option_values = Array::Handle(isolate);
-    reply_port ^= msg.At(1);
-    path ^= msg.At(2);
-    option_keys ^= msg.At(3);
-    option_values ^= msg.At(4);
-
-    ASSERT(!path.IsNull());
-    ASSERT(!option_keys.IsNull());
-    ASSERT(!option_values.IsNull());
-    // Same number of option keys as values.
-    ASSERT(option_keys.Length() == option_values.Length());
-
-    if (!reply_port.IsSendPort()) {
-      FATAL("SendPort expected.");
-    }
-
-    String& path_segment = String::Handle();
-    if (path.Length() > 0) {
-      path_segment ^= path.At(0);
-    } else {
-      path_segment ^= Symbols::Empty().raw();
-    }
-    ASSERT(!path_segment.IsNull());
-    const char* path_segment_c = path_segment.ToCString();
-
-    IsolateMessageHandler handler =
-        FindIsolateMessageHandler(path_segment_c);
-    {
-      JSONStream js;
-      js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
-               path, option_keys, option_values);
-      if (handler == NULL) {
-        // Check for an embedder handler.
-        EmbedderServiceHandler* e_handler =
-            FindIsolateEmbedderHandler(path_segment_c);
-        if (e_handler != NULL) {
-          EmbedderHandleMessage(e_handler, &js);
-        } else {
-          PrintError(&js, "Unrecognized path");
-        }
-        js.PostReply();
-      } else {
-        if (handler(isolate, &js)) {
-          // Handler returns true if the reply is ready to be posted.
-          // TODO(johnmccutchan): Support asynchronous replies.
-          js.PostReply();
-        }
-      }
-    }
-  }
-}
-
-
 static bool HandleIsolate(Isolate* isolate, JSONStream* js) {
   isolate->PrintJSON(js, false);
   return true;
@@ -1072,8 +1007,8 @@
 
 static bool HandleCommonEcho(JSONObject* jsobj, JSONStream* js) {
   jsobj->AddProperty("type", "_EchoResponse");
-  if (js->HasOption("text")) {
-    jsobj->AddProperty("text", js->LookupOption("text"));
+  if (js->HasParam("text")) {
+    jsobj->AddProperty("text", js->LookupParam("text"));
   }
   return true;
 }
@@ -1098,7 +1033,7 @@
 
 
 static bool HandleIsolateTriggerEchoEvent(Isolate* isolate, JSONStream* js) {
-  Service::SendEchoEvent(isolate, js->LookupOption("text"));
+  Service::SendEchoEvent(isolate, js->LookupParam("text"));
   JSONObject jsobj(js);
   return HandleCommonEcho(&jsobj, js);
 }
@@ -1110,26 +1045,6 @@
 }
 
 
-// Print an error message if there is no ID argument.
-#define REQUIRE_COLLECTION_ID(collection)                                      \
-  if (js->num_arguments() == 1) {                                              \
-    PrintError(js, "Must specify collection object id: /%s/id", collection);   \
-    return true;                                                               \
-  }
-
-
-#define CHECK_COLLECTION_ID_BOUNDS(collection, length, arg, id, js)            \
-  if (!GetIntegerId(arg, &id)) {                                               \
-    PrintError(js, "Must specify collection object id: %s/id", collection);    \
-    return true;                                                               \
-  }                                                                            \
-  if ((id < 0) || (id >= length)) {                                            \
-    PrintError(js, "%s id (%" Pd ") must be in [0, %" Pd ").", collection, id, \
-                                                               length);        \
-    return true;                                                               \
-  }
-
-
 static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
   if ((s == NULL) || (*s == '\0')) {
     // Empty string.
@@ -1680,19 +1595,19 @@
 
 static bool HandleIsolateGetInboundReferences(Isolate* isolate,
                                               JSONStream* js) {
-  const char* target_id = js->LookupOption("targetId");
+  const char* target_id = js->LookupParam("targetId");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'targetId' option");
+    PrintMissingParamError(js, "targetId");
     return true;
   }
-  const char* limit_cstr = js->LookupOption("limit");
+  const char* limit_cstr = js->LookupParam("limit");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'limit' option");
+    PrintMissingParamError(js, "limit");
     return true;
   }
   intptr_t limit;
-  if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
-    PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+  if (!GetIntegerId(limit_cstr, &limit)) {
+    PrintInvalidParamError(js, "limit");
     return true;
   }
 
@@ -1706,18 +1621,15 @@
     if (lookup_result == ObjectIdRing::kCollected) {
       PrintErrorWithKind(
           js, "InboundReferencesCollected",
-          "attempt to find a retaining path for a collected object\n",
-          js->num_arguments());
+          "attempt to find a retaining path for a collected object\n");
       return true;
     } else if (lookup_result == ObjectIdRing::kExpired) {
       PrintErrorWithKind(
           js, "InboundReferencesExpired",
-          "attempt to find a retaining path for an expired object\n",
-          js->num_arguments());
+          "attempt to find a retaining path for an expired object\n");
       return true;
     }
-    PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
-               target_id);
+    PrintInvalidParamError(js, "targetId");
     return true;
   }
   return PrintInboundReferences(isolate, &obj, limit, js);
@@ -1781,19 +1693,19 @@
 
 static bool HandleIsolateGetRetainingPath(Isolate* isolate,
                                           JSONStream* js) {
-  const char* target_id = js->LookupOption("targetId");
+  const char* target_id = js->LookupParam("targetId");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'targetId' option");
+    PrintMissingParamError(js, "targetId");
     return true;
   }
-  const char* limit_cstr = js->LookupOption("limit");
+  const char* limit_cstr = js->LookupParam("limit");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'limit' option");
+    PrintMissingParamError(js, "limit");
     return true;
   }
   intptr_t limit;
-  if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
-    PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+  if (!GetIntegerId(limit_cstr, &limit)) {
+    PrintInvalidParamError(js, "limit");
     return true;
   }
 
@@ -1807,18 +1719,15 @@
     if (lookup_result == ObjectIdRing::kCollected) {
       PrintErrorWithKind(
           js, "RetainingPathCollected",
-          "attempt to find a retaining path for a collected object\n",
-          js->num_arguments());
+          "attempt to find a retaining path for a collected object\n");
       return true;
     } else if (lookup_result == ObjectIdRing::kExpired) {
       PrintErrorWithKind(
           js, "RetainingPathExpired",
-          "attempt to find a retaining path for an expired object\n",
-          js->num_arguments());
+          "attempt to find a retaining path for an expired object\n");
       return true;
     }
-    PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
-               target_id);
+    PrintInvalidParamError(js, "targetId");
     return true;
   }
   return PrintRetainingPath(isolate, &obj, limit, js);
@@ -1826,9 +1735,9 @@
 
 
 static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) {
-  const char* target_id = js->LookupOption("targetId");
+  const char* target_id = js->LookupParam("targetId");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'targetId' option");
+    PrintMissingParamError(js, "targetId");
     return true;
   }
   ObjectIdRing::LookupResult lookup_result;
@@ -1838,18 +1747,15 @@
     if (lookup_result == ObjectIdRing::kCollected) {
       PrintErrorWithKind(
           js, "RetainedCollected",
-          "attempt to calculate size retained by a collected object\n",
-          js->num_arguments());
+          "attempt to calculate size retained by a collected object\n");
       return true;
     } else if (lookup_result == ObjectIdRing::kExpired) {
       PrintErrorWithKind(
           js, "RetainedExpired",
-          "attempt to calculate size retained by an expired object\n",
-          js->num_arguments());
+          "attempt to calculate size retained by an expired object\n");
       return true;
     }
-    PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
-               target_id);
+    PrintInvalidParamError(js, "targetId");
     return true;
   }
   if (obj.IsClass()) {
@@ -1868,43 +1774,22 @@
     result.PrintJSON(js, true);
     return true;
   }
-  PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
-             "library, class, or instance", target_id);
-  return true;
-}
-
-
-static bool HandleClassesClosures(Isolate* isolate, const Class& cls,
-                                  JSONStream* js) {
-  intptr_t id;
-  if (js->num_arguments() > 4) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  if (!GetIntegerId(js->GetArgument(3), &id)) {
-    PrintError(js, "Must specify collection object id: closures/id");
-    return true;
-  }
-  Function& func = Function::Handle();
-  func ^= cls.ClosureFunctionFromIndex(id);
-  if (func.IsNull()) {
-    PrintError(js, "Closure function %" Pd " not found", id);
-    return true;
-  }
-  func.PrintJSON(js, false);
+  PrintError(js, "%s: Invalid 'targetId' parameter value: "
+             "id '%s' does not correspond to a "
+             "library, class, or instance", js->method(), target_id);
   return true;
 }
 
 
 static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) {
-  const char* target_id = js->LookupOption("targetId");
+  const char* target_id = js->LookupParam("targetId");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'targetId' option");
+    PrintMissingParamError(js, "targetId");
     return true;
   }
-  const char* expr = js->LookupOption("expression");
+  const char* expr = js->LookupParam("expression");
   if (expr == NULL) {
-    PrintError(js, "Missing 'expression' option");
+    PrintMissingParamError(js, "expression");
     return true;
   }
   const String& expr_str = String::Handle(isolate, String::New(expr));
@@ -1917,8 +1802,7 @@
     } else if (lookup_result == ObjectIdRing::kExpired) {
       PrintSentinel(js, "objects/expired", "<expired>");
     } else {
-      PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
-                 target_id);
+      PrintInvalidParamError(js, "targetId");
     }
     return true;
   }
@@ -1950,173 +1834,9 @@
     result.PrintJSON(js, true);
     return true;
   }
-  PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
-             "library, class, or instance", target_id);
-  return true;
-}
-
-
-static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls,
-                                     JSONStream* js) {
-  intptr_t id;
-  if (js->num_arguments() > 4) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  if (!GetIntegerId(js->GetArgument(3), &id)) {
-    PrintError(js, "Must specify collection object id: dispatchers/id");
-    return true;
-  }
-  Function& func = Function::Handle();
-  func ^= cls.InvocationDispatcherFunctionFromIndex(id);
-  if (func.IsNull()) {
-    PrintError(js, "Dispatcher %" Pd " not found", id);
-    return true;
-  }
-  func.PrintJSON(js, false);
-  return true;
-}
-
-
-static bool HandleFunctionSetSource(
-    Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) {
-  if (js->LookupOption("source") == NULL) {
-    PrintError(js, "set_source expects a 'source' option\n");
-    return true;
-  }
-  const String& source =
-      String::Handle(String::New(js->LookupOption("source")));
-  const Object& result = Object::Handle(
-      Parser::ParseFunctionFromSource(cls, source));
-  if (result.IsError()) {
-    Error::Cast(result).PrintJSON(js, false);
-    return true;
-  }
-  if (!result.IsFunction()) {
-    PrintError(js, "source did not compile to a function.\n");
-    return true;
-  }
-
-  // Replace function.
-  cls.RemoveFunction(func);
-  cls.AddFunction(Function::Cast(result));
-
-  JSONObject jsobj(js);
-  jsobj.AddProperty("type", "Success");
-  jsobj.AddProperty("id", "");
-  return true;
-}
-
-
-static bool HandleClassesFunctions(Isolate* isolate, const Class& cls,
-                                   JSONStream* js) {
-  if (js->num_arguments() != 4 && js->num_arguments() != 5) {
-    PrintError(js, "Command should have 4 or 5 arguments");
-    return true;
-  }
-  const char* encoded_id = js->GetArgument(3);
-  String& id = String::Handle(isolate, String::New(encoded_id));
-  id = String::DecodeIRI(id);
-  if (id.IsNull()) {
-    PrintError(js, "Function id %s is malformed", encoded_id);
-    return true;
-  }
-  Function& func = Function::Handle(cls.LookupFunction(id));
-  if (func.IsNull()) {
-    PrintError(js, "Function %s not found", encoded_id);
-    return true;
-  }
-  if (js->num_arguments() == 4) {
-    func.PrintJSON(js, false);
-    return true;
-  } else {
-    const char* subcommand = js->GetArgument(4);
-    if (strcmp(subcommand, "set_source") == 0) {
-      return HandleFunctionSetSource(isolate, cls, func, js);
-    } else {
-      PrintError(js, "Invalid sub command %s", subcommand);
-      return true;
-    }
-  }
-  UNREACHABLE();
-  return true;
-}
-
-
-static bool HandleClassesImplicitClosures(Isolate* isolate, const Class& cls,
-                                          JSONStream* js) {
-  intptr_t id;
-  if (js->num_arguments() > 4) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  if (!GetIntegerId(js->GetArgument(3), &id)) {
-    PrintError(js, "Must specify collection object id: implicit_closures/id");
-    return true;
-  }
-  Function& func = Function::Handle();
-  func ^= cls.ImplicitClosureFunctionFromIndex(id);
-  if (func.IsNull()) {
-    PrintError(js, "Implicit closure function %" Pd " not found", id);
-    return true;
-  }
-  func.PrintJSON(js, false);
-  return true;
-}
-
-
-static bool HandleClassesFields(Isolate* isolate, const Class& cls,
-                                JSONStream* js) {
-  intptr_t id;
-  if (js->num_arguments() > 4) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  if (!GetIntegerId(js->GetArgument(3), &id)) {
-    PrintError(js, "Must specify collection object id: fields/id");
-    return true;
-  }
-  Field& field = Field::Handle(cls.FieldFromIndex(id));
-  if (field.IsNull()) {
-    PrintError(js, "Field %" Pd " not found", id);
-    return true;
-  }
-  field.PrintJSON(js, false);
-  return true;
-}
-
-
-static bool HandleClassesTypes(Isolate* isolate, const Class& cls,
-                               JSONStream* js) {
-  if (js->num_arguments() == 3) {
-    JSONObject jsobj(js);
-    jsobj.AddProperty("type", "TypeList");
-    JSONArray members(&jsobj, "members");
-    const intptr_t num_types = cls.NumCanonicalTypes();
-    Type& type = Type::Handle();
-    for (intptr_t i = 0; i < num_types; i++) {
-      type = cls.CanonicalTypeFromIndex(i);
-      members.AddValue(type);
-    }
-    return true;
-  }
-  if (js->num_arguments() > 4) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  ASSERT(js->num_arguments() == 4);
-  intptr_t id;
-  if (!GetIntegerId(js->GetArgument(3), &id)) {
-    PrintError(js, "Must specify collection object id: types/id");
-    return true;
-  }
-  Type& type = Type::Handle();
-  type ^= cls.CanonicalTypeFromIndex(id);
-  if (type.IsNull()) {
-    PrintError(js, "Canonical type %" Pd " not found", id);
-    return true;
-  }
-  type.PrintJSON(js, false);
+  PrintError(js, "%s: Invalid 'targetId' parameter value: "
+             "id '%s' does not correspond to a "
+             "library, class, or instance", js->method(), target_id);
   return true;
 }
 
@@ -2154,26 +1874,26 @@
 
 
 static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) {
-  const char* target_id = js->LookupOption("classId");
+  const char* target_id = js->LookupParam("classId");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'classId' option");
+    PrintMissingParamError(js, "classId");
     return true;
   }
-  const char* limit_cstr = js->LookupOption("limit");
+  const char* limit_cstr = js->LookupParam("limit");
   if (target_id == NULL) {
-    PrintError(js, "Missing 'limit' option");
+    PrintMissingParamError(js, "limit");
     return true;
   }
   intptr_t limit;
-  if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
-    PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+  if (!GetIntegerId(limit_cstr, &limit)) {
+    PrintInvalidParamError(js, "limit");
     return true;
   }
   const Object& obj =
       Object::Handle(LookupHeapObject(isolate, target_id, NULL));
   if (obj.raw() == Object::sentinel().raw() ||
       !obj.IsClass()) {
-    PrintError(js, "Invalid 'classId' value: no class with id '%s'", target_id);
+    PrintInvalidParamError(js, "classId");
     return true;
   }
   const Class& cls = Class::Cast(obj);
@@ -2199,60 +1919,15 @@
 }
 
 
-static bool HandleClasses(Isolate* isolate, JSONStream* js) {
-  if (js->num_arguments() == 1) {
-    PrintError(js, "Invalid number of arguments.");
-    return true;
-  }
-  ASSERT(js->num_arguments() >= 2);
-  intptr_t id;
-  if (!GetIntegerId(js->GetArgument(1), &id)) {
-    PrintError(js, "Must specify collection object id: /classes/id");
-    return true;
-  }
-  ClassTable* table = isolate->class_table();
-  if (!table->IsValidIndex(id)) {
-    PrintError(js, "%" Pd " is not a valid class id.", id);
-    return true;
-  }
-  Class& cls = Class::Handle(table->At(id));
-  if (js->num_arguments() == 2) {
-    cls.PrintJSON(js, false);
-    return true;
-  } else if (js->num_arguments() >= 3) {
-    const char* second = js->GetArgument(2);
-    if (strcmp(second, "closures") == 0) {
-      return HandleClassesClosures(isolate, cls, js);
-    } else if (strcmp(second, "fields") == 0) {
-      return HandleClassesFields(isolate, cls, js);
-    } else if (strcmp(second, "functions") == 0) {
-      return HandleClassesFunctions(isolate, cls, js);
-    } else if (strcmp(second, "implicit_closures") == 0) {
-      return HandleClassesImplicitClosures(isolate, cls, js);
-    } else if (strcmp(second, "dispatchers") == 0) {
-      return HandleClassesDispatchers(isolate, cls, js);
-    } else if (strcmp(second, "types") == 0) {
-      return HandleClassesTypes(isolate, cls, js);
-    } else {
-      PrintError(js, "Invalid sub collection %s", second);
-      return true;
-    }
-  }
-  UNREACHABLE();
-  return true;
-}
-
-
 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
-  if (!js->HasOption("targetId")) {
+  if (!js->HasParam("targetId")) {
     CodeCoverage::PrintJSON(isolate, js, NULL);
     return true;
   }
-  const char* target_id = js->LookupOption("targetId");
+  const char* target_id = js->LookupParam("targetId");
   Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL));
   if (obj.raw() == Object::sentinel().raw()) {
-    PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
-               target_id);
+    PrintInvalidParamError(js, "targetId");
     return true;
   }
   if (obj.IsScript()) {
@@ -2275,27 +1950,28 @@
     CodeCoverage::PrintJSON(isolate, js, &ff);
     return true;
   }
-  PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
-             "script, library, class, or function", target_id);
+  PrintError(js, "%s: Invalid 'targetId' parameter value: "
+             "id '%s' does not correspond to a "
+             "script, library, class, or function", js->method(), target_id);
   return true;
 }
 
 
 static bool HandleIsolateAddBreakpoint(Isolate* isolate, JSONStream* js) {
-  if (!js->HasOption("line")) {
-    PrintError(js, "Missing 'line' option");
+  if (!js->HasParam("line")) {
+    PrintMissingParamError(js, "line");
     return true;
   }
-  const char* line_option = js->LookupOption("line");
+  const char* line_param = js->LookupParam("line");
   intptr_t line = -1;
-  if (!GetIntegerId(line_option, &line)) {
-    PrintError(js, "Invalid 'line' value: %s is not an integer", line_option);
+  if (!GetIntegerId(line_param, &line)) {
+    PrintInvalidParamError(js, "line");
     return true;
   }
-  const char* script_id = js->LookupOption("script");
+  const char* script_id = js->LookupParam("script");
   Object& obj = Object::Handle(LookupHeapObject(isolate, script_id, NULL));
   if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
-    PrintError(js, "Invalid 'script' value: no script with id '%s'", script_id);
+    PrintInvalidParamError(js, "script");
     return true;
   }
   const Script& script = Script::Cast(obj);
@@ -2303,7 +1979,7 @@
   SourceBreakpoint* bpt =
       isolate->debugger()->SetBreakpointAtLine(script_url, line);
   if (bpt == NULL) {
-    PrintError(js, "Unable to set breakpoint at line %s", line_option);
+    PrintError(js, "Unable to set breakpoint at line %s", line_param);
     return true;
   }
   bpt->PrintJSON(js);
@@ -2312,16 +1988,15 @@
 
 
 static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) {
-  if (!js->HasOption("breakpointId")) {
-    PrintError(js, "Missing 'breakpointId' option");
+  if (!js->HasParam("breakpointId")) {
+    PrintMissingParamError(js, "breakpointId");
     return true;
   }
-  const char* bpt_id = js->LookupOption("breakpointId");
+  const char* bpt_id = js->LookupParam("breakpointId");
   SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
   if (bpt == NULL) {
     fprintf(stderr, "ERROR1");
-    PrintError(js, "Invalid 'breakpointId' value: no breakpoint with id '%s'",
-               bpt_id);
+    PrintInvalidParamError(js, "breakpointId");
     return true;
   }
   isolate->debugger()->RemoveBreakpoint(bpt->id());
@@ -2335,75 +2010,6 @@
 }
 
 
-static bool HandleLibrariesScripts(Isolate* isolate,
-                                   const Library& lib,
-                                   JSONStream* js) {
-  if (js->num_arguments() > 5) {
-    PrintError(js, "Command too long");
-    return true;
-  } else if (js->num_arguments() < 4) {
-    PrintError(js, "Must specify collection object id: scripts/id");
-    return true;
-  }
-  const String& id = String::Handle(String::New(js->GetArgument(3)));
-  ASSERT(!id.IsNull());
-  // The id is the url of the script % encoded, decode it.
-  const String& requested_url = String::Handle(String::DecodeIRI(id));
-  Script& script = Script::Handle();
-  String& script_url = String::Handle();
-  const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
-  ASSERT(!loaded_scripts.IsNull());
-  intptr_t i;
-  for (i = 0; i < loaded_scripts.Length(); i++) {
-    script ^= loaded_scripts.At(i);
-    ASSERT(!script.IsNull());
-    script_url ^= script.url();
-    if (script_url.Equals(requested_url)) {
-      break;
-    }
-  }
-  if (i == loaded_scripts.Length()) {
-    PrintError(js, "Script %s not found", requested_url.ToCString());
-    return true;
-  }
-  if (js->num_arguments() > 4) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  script.PrintJSON(js, false);
-  return true;
-}
-
-
-static bool HandleLibraries(Isolate* isolate, JSONStream* js) {
-  // TODO(johnmccutchan): Support fields and functions on libraries.
-  REQUIRE_COLLECTION_ID("libraries");
-  const GrowableObjectArray& libs =
-      GrowableObjectArray::Handle(isolate->object_store()->libraries());
-  ASSERT(!libs.IsNull());
-  intptr_t id = 0;
-  CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1),
-                             id, js);
-  Library& lib = Library::Handle();
-  lib ^= libs.At(id);
-  ASSERT(!lib.IsNull());
-  if (js->num_arguments() == 2) {
-    lib.PrintJSON(js, false);
-    return true;
-  } else if (js->num_arguments() >= 3) {
-    const char* second = js->GetArgument(2);
-    if (strcmp(second, "scripts") == 0) {
-      return HandleLibrariesScripts(isolate, lib, js);
-    } else {
-      PrintError(js, "Invalid sub collection %s", second);
-      return true;
-    }
-  }
-  UNREACHABLE();
-  return true;
-}
-
-
 static RawClass* GetMetricsClass(Isolate* isolate) {
   const Library& prof_lib =
       Library::Handle(isolate, Library::ProfilerLibrary());
@@ -2500,18 +2106,17 @@
 
 static bool HandleIsolateGetMetricList(Isolate* isolate, JSONStream* js) {
   bool native_metrics = false;
-  if (js->HasOption("type")) {
-    if (js->OptionIs("type", "Native")) {
+  if (js->HasParam("type")) {
+    if (js->ParamIs("type", "Native")) {
       native_metrics = true;
-    } else if (js->OptionIs("type", "Dart")) {
+    } else if (js->ParamIs("type", "Dart")) {
       native_metrics = false;
     } else {
-      PrintError(js, "Invalid 'type' option value: %s\n",
-                 js->LookupOption("type"));
+      PrintInvalidParamError(js, "type");
       return true;
     }
   } else {
-    PrintError(js, "Expected 'type' option.");
+    PrintMissingParamError(js, "type");
     return true;
   }
   if (native_metrics) {
@@ -2522,9 +2127,9 @@
 
 
 static bool HandleIsolateGetMetric(Isolate* isolate, JSONStream* js) {
-  const char* metric_id = js->LookupOption("metricId");
+  const char* metric_id = js->LookupParam("metricId");
   if (metric_id == NULL) {
-    PrintError(js, "Expected 'metricId' option.");
+    PrintMissingParamError(js, "metricId");
     return true;
   }
   // Verify id begins with "metrics/".
@@ -2553,114 +2158,16 @@
 
 
 static bool HandleVMGetMetric(JSONStream* js) {
-  const char* metric_id = js->LookupOption("metricId");
+  const char* metric_id = js->LookupParam("metricId");
   if (metric_id == NULL) {
-    PrintError(js, "Expected 'metricId' option.");
+    PrintMissingParamError(js, "metricId");
   }
   return false;
 }
 
 
-static bool HandleObjects(Isolate* isolate, JSONStream* js) {
-  REQUIRE_COLLECTION_ID("objects");
-  if (js->num_arguments() != 2) {
-    PrintError(js, "expected at least 2 arguments but found %" Pd "\n",
-               js->num_arguments());
-    return true;
-  }
-  const char* arg = js->GetArgument(1);
-
-  // Handle special non-objects first.
-  if (strcmp(arg, "optimized-out") == 0) {
-    if (js->num_arguments() > 2) {
-      PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
-                 js->num_arguments());
-    } else {
-      Symbols::OptimizedOut().PrintJSON(js, false);
-    }
-    return true;
-
-  } else if (strcmp(arg, "collected") == 0) {
-    if (js->num_arguments() > 2) {
-      PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
-                 js->num_arguments());
-    } else {
-      PrintSentinel(js, "objects/collected", "<collected>");
-    }
-    return true;
-
-  } else if (strcmp(arg, "expired") == 0) {
-    if (js->num_arguments() > 2) {
-      PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
-                 js->num_arguments());
-    } else {
-      PrintSentinel(js, "objects/expired", "<expired>");
-    }
-    return true;
-  }
-
-  // Lookup the object.
-  Object& obj = Object::Handle(isolate);
-  ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
-  obj = LookupObjectId(isolate, arg, &kind);
-  if (kind == ObjectIdRing::kInvalid) {
-    PrintError(js, "unrecognized object id '%s'", arg);
-    return true;
-  }
-
-  // Print.
-  if (kind == ObjectIdRing::kCollected) {
-    // The object has been collected by the gc.
-    PrintSentinel(js, "objects/collected", "<collected>");
-    return true;
-  } else if (kind == ObjectIdRing::kExpired) {
-    // The object id has expired.
-    PrintSentinel(js, "objects/expired", "<expired>");
-    return true;
-  }
-  obj.PrintJSON(js, false);
-  return true;
-}
-
-
-static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) {
-  JSONObject jsobj(js);
-  jsobj.AddProperty("type", "ScriptList");
-  jsobj.AddProperty("id", "scripts");
-  JSONArray members(&jsobj, "members");
-  const GrowableObjectArray& libs =
-      GrowableObjectArray::Handle(isolate->object_store()->libraries());
-  intptr_t num_libs = libs.Length();
-  Library &lib = Library::Handle();
-  Script& script = Script::Handle();
-  for (intptr_t i = 0; i < num_libs; i++) {
-    lib ^= libs.At(i);
-    ASSERT(!lib.IsNull());
-    ASSERT(Smi::IsValid(lib.index()));
-    const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
-    ASSERT(!loaded_scripts.IsNull());
-    intptr_t num_scripts = loaded_scripts.Length();
-    for (intptr_t i = 0; i < num_scripts; i++) {
-      script ^= loaded_scripts.At(i);
-      members.AddValue(script);
-    }
-  }
-  return true;
-}
-
-
-static bool HandleScripts(Isolate* isolate, JSONStream* js) {
-  if (js->num_arguments() == 1) {
-    // Enumerate all scripts.
-    return HandleScriptsEnumerate(isolate, js);
-  }
-  PrintError(js, "Command too long");
-  return true;
-}
-
-
 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) {
-  const char* step_option = js->LookupOption("step");
+  const char* step_param = js->LookupParam("step");
   if (isolate->message_handler()->paused_on_start()) {
     isolate->message_handler()->set_pause_on_start(false);
     JSONObject jsobj(js);
@@ -2676,15 +2183,15 @@
     return true;
   }
   if (isolate->debugger()->PauseEvent() != NULL) {
-    if (step_option != NULL) {
-      if (strcmp(step_option, "into") == 0) {
+    if (step_param != NULL) {
+      if (strcmp(step_param, "into") == 0) {
         isolate->debugger()->SetSingleStep();
-      } else if (strcmp(step_option, "over") == 0) {
+      } else if (strcmp(step_param, "over") == 0) {
         isolate->debugger()->SetStepOver();
-      } else if (strcmp(step_option, "out") == 0) {
+      } else if (strcmp(step_param, "out") == 0) {
         isolate->debugger()->SetStepOut();
       } else {
-        PrintError(js, "Invalid 'step' option: %s", step_option);
+        PrintInvalidParamError(js, "step");
         return true;
       }
     }
@@ -2719,69 +2226,6 @@
 }
 
 
-static bool HandleNullCode(uintptr_t pc, JSONStream* js) {
-  // TODO(turnidge): Consider adding/using Object::null_code() for
-  // consistent "type".
-  Object::null_object().PrintJSON(js, false);
-  return true;
-}
-
-
-static bool HandleCode(Isolate* isolate, JSONStream* js) {
-  REQUIRE_COLLECTION_ID("code");
-  uword pc;
-  if (js->num_arguments() > 2) {
-    PrintError(js, "Command too long");
-    return true;
-  }
-  ASSERT(js->num_arguments() == 2);
-  static const char* kCollectedPrefix = "collected-";
-  static intptr_t kCollectedPrefixLen = strlen(kCollectedPrefix);
-  static const char* kNativePrefix = "native-";
-  static intptr_t kNativePrefixLen = strlen(kNativePrefix);
-  static const char* kReusedPrefix = "reused-";
-  static intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
-  const char* command = js->GetArgument(1);
-  if (strncmp(kCollectedPrefix, command, kCollectedPrefixLen) == 0) {
-    if (!GetUnsignedIntegerId(&command[kCollectedPrefixLen], &pc, 16)) {
-      PrintError(js, "Must specify code address: code/%sc0deadd0.",
-                 kCollectedPrefix);
-      return true;
-    }
-    return HandleNullCode(pc, js);
-  }
-  if (strncmp(kNativePrefix, command, kNativePrefixLen) == 0) {
-    if (!GetUnsignedIntegerId(&command[kNativePrefixLen], &pc, 16)) {
-      PrintError(js, "Must specify code address: code/%sc0deadd0.",
-                 kNativePrefix);
-      return true;
-    }
-    // TODO(johnmccutchan): Support native Code.
-    return HandleNullCode(pc, js);
-  }
-  if (strncmp(kReusedPrefix, command, kReusedPrefixLen) == 0) {
-    if (!GetUnsignedIntegerId(&command[kReusedPrefixLen], &pc, 16)) {
-      PrintError(js, "Must specify code address: code/%sc0deadd0.",
-                 kReusedPrefix);
-      return true;
-    }
-    return HandleNullCode(pc, js);
-  }
-  int64_t timestamp = 0;
-  if (!GetCodeId(command, &timestamp, &pc) || (timestamp < 0)) {
-    PrintError(js, "Malformed code id: %s", command);
-    return true;
-  }
-  Code& code = Code::Handle(Code::FindCode(pc, timestamp));
-  if (!code.IsNull()) {
-    code.PrintJSON(js, false);
-    return true;
-  }
-  PrintError(js, "Could not find code with id: %s", command);
-  return true;
-}
-
-
 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
   JSONObject miniProfile(js);
   miniProfile.AddProperty("type", "TagProfile");
@@ -2792,23 +2236,22 @@
 
 static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
   // A full profile includes disassembly of all Dart code objects.
-  // TODO(johnmccutchan): Add sub command to trigger full code dump.
+  // TODO(johnmccutchan): Add option to trigger full code dump.
   bool full_profile = false;
-  const char* tags_option = js->LookupOption("tags");
   Profiler::TagOrder tag_order = Profiler::kUserVM;
-  if (js->HasOption("tags")) {
-    if (js->OptionIs("tags", "None")) {
+  if (js->HasParam("tags")) {
+    if (js->ParamIs("tags", "None")) {
       tag_order = Profiler::kNoTags;
-    } else if (js->OptionIs("tags", "UserVM")) {
+    } else if (js->ParamIs("tags", "UserVM")) {
       tag_order = Profiler::kUserVM;
-    } else if (js->OptionIs("tags", "UserOnly")) {
+    } else if (js->ParamIs("tags", "UserOnly")) {
       tag_order = Profiler::kUser;
-    } else if (js->OptionIs("tags", "VMUser")) {
+    } else if (js->ParamIs("tags", "VMUser")) {
       tag_order = Profiler::kVMUser;
-    } else if (js->OptionIs("tags", "VMOnly")) {
+    } else if (js->ParamIs("tags", "VMOnly")) {
       tag_order = Profiler::kVM;
     } else {
-      PrintError(js, "Invalid tags option value: %s\n", tags_option);
+      PrintInvalidParamError(js, "tags");
       return true;
     }
   }
@@ -2821,20 +2264,19 @@
                                               JSONStream* js) {
   bool should_reset_accumulator = false;
   bool should_collect = false;
-  if (js->HasOption("reset")) {
-    if (js->OptionIs("reset", "true")) {
+  if (js->HasParam("reset")) {
+    if (js->ParamIs("reset", "true")) {
       should_reset_accumulator = true;
     } else {
-      PrintError(js, "Unrecognized reset option '%s'",
-                 js->LookupOption("reset"));
+      PrintInvalidParamError(js, "reset");
       return true;
     }
   }
-  if (js->HasOption("gc")) {
-    if (js->OptionIs("gc", "full")) {
+  if (js->HasParam("gc")) {
+    if (js->ParamIs("gc", "full")) {
       should_collect = true;
     } else {
-      PrintError(js, "Unrecognized gc option '%s'", js->LookupOption("gc"));
+      PrintInvalidParamError(js, "gc");
       return true;
     }
   }
@@ -2907,15 +2349,20 @@
 };
 
 
-static bool HandleAddress(Isolate* isolate, JSONStream* js) {
-  uword addr = 0;
-  if (js->num_arguments() != 2 ||
-      !GetUnsignedIntegerId(js->GetArgument(1), &addr, 16)) {
-    static const uword kExampleAddr = static_cast<uword>(kIntptrMax / 7);
-    PrintError(js, "Must specify address: address/" Px ".", kExampleAddr);
+static bool HandleIsolateGetObjectByAddress(Isolate* isolate, JSONStream* js) {
+  const char* addr_str = js->LookupParam("address");
+  if (addr_str == NULL) {
+    PrintMissingParamError(js, "address");
     return true;
   }
-  bool ref = js->HasOption("ref") && js->OptionIs("ref", "true");
+
+  // Handle heap objects.
+  uword addr = 0;
+  if (!GetUnsignedIntegerId(addr_str, &addr, 16)) {
+    PrintInvalidParamError(js, "address");
+    return true;
+  }
+  bool ref = js->HasParam("ref") && js->ParamIs("ref", "true");
   Object& object = Object::Handle(isolate);
   {
     NoGCScope no_gc;
@@ -2949,39 +2396,10 @@
 }
 
 
-static IsolateMessageHandlerEntry isolate_handlers[] = {
-  { "", HandleIsolate },                          // getObject
-  { "address", HandleAddress },                   // to do
-  { "classes", HandleClasses },                   // getObject
-  { "code", HandleCode },                         // getObject
-  { "libraries", HandleLibraries },               // getObject
-  { "objects", HandleObjects },                   // getObject
-  { "scripts", HandleScripts },                   // getObject
-};
-
-
-static IsolateMessageHandler FindIsolateMessageHandler(const char* command) {
-  intptr_t num_message_handlers = sizeof(isolate_handlers) /
-                                  sizeof(isolate_handlers[0]);
-  for (intptr_t i = 0; i < num_message_handlers; i++) {
-    const IsolateMessageHandlerEntry& entry = isolate_handlers[i];
-    if (strcmp(command, entry.command) == 0) {
-      return entry.handler;
-    }
-  }
-  if (FLAG_trace_service) {
-    OS::Print("vm-service: No isolate message handler for <%s>.\n", command);
-  }
-  return NULL;
-}
-
-
 static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) {
-  const char* id = js->LookupOption("objectId");
+  const char* id = js->LookupParam("objectId");
   if (id == NULL) {
-    // TODO(turnidge): Print the isolate here instead.
-    PrintError(js, "GetObject expects an 'objectId' parameter\n",
-               js->num_arguments());
+    PrintMissingParamError(js, "objectId");
     return true;
   }
 
@@ -2995,8 +2413,10 @@
     return true;
   } else if (lookup_result == ObjectIdRing::kCollected) {
     PrintSentinel(js, "objects/collected", "<collected>");
+    return true;
   } else if (lookup_result == ObjectIdRing::kExpired) {
     PrintSentinel(js, "objects/expired", "<expired>");
+    return true;
   }
 
   // Handle non-heap objects.
@@ -3022,7 +2442,7 @@
 static bool HandleIsolateGetTypeArgumentsList(Isolate* isolate,
                                               JSONStream* js) {
   bool only_with_instantiations = false;
-  if (js->OptionIs("onlyWithInstantiations", "true")) {
+  if (js->ParamIs("onlyWithInstantiations", "true")) {
     only_with_instantiations = true;
   }
   ObjectStore* object_store = isolate->object_store();
@@ -3051,6 +2471,7 @@
 static IsolateMessageHandlerEntry isolate_handlers_new[] = {
   { "getIsolate", HandleIsolate },
   { "getObject", HandleIsolateGetObject },
+  { "getObjectByAddress", HandleIsolateGetObjectByAddress },
   { "getBreakpoints", HandleIsolateGetBreakpoints },
   { "pause", HandleIsolatePause },
   { "resume", HandleIsolateResume },
@@ -3079,33 +2500,33 @@
 };
 
 
-static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command) {
+static IsolateMessageHandler FindIsolateMessageHandler(const char* method) {
   intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
                                   sizeof(isolate_handlers_new[0]);
   for (intptr_t i = 0; i < num_message_handlers; i++) {
     const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
-    if (strcmp(command, entry.command) == 0) {
+    if (strcmp(method, entry.method) == 0) {
       return entry.handler;
     }
   }
   if (FLAG_trace_service) {
-    OS::Print("Service has no isolate message handler for <%s>\n", command);
+    OS::Print("Service has no isolate message handler for <%s>\n", method);
   }
   return NULL;
 }
 
 
-void Service::HandleRootMessageNew(const Array& msg) {
+void Service::HandleRootMessage(const Instance& msg_instance) {
   Isolate* isolate = Isolate::Current();
-  ASSERT(!msg.IsNull());
+  ASSERT(!msg_instance.IsNull());
+  ASSERT(msg_instance.IsArray());
 
   {
     StackZone zone(isolate);
     HANDLESCOPE(isolate);
 
-    const Array& message = Array::Cast(msg);
-    // Message is a list with five entries.
-    ASSERT(message.Length() == 5);
+    const Array& msg = Array::Cast(msg_instance);
+    ASSERT(msg.Length() == 5);
 
     Instance& reply_port = Instance::Handle(isolate);
     String& method = String::Handle(isolate);
@@ -3126,11 +2547,11 @@
     }
 
     RootMessageHandler handler =
-        FindRootMessageHandlerNew(method.ToCString());
+        FindRootMessageHandler(method.ToCString());
     {
       JSONStream js;
-      js.SetupNew(zone.GetZone(), SendPort::Cast(reply_port).Id(),
-                  method, param_keys, param_values);
+      js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
+               method, param_keys, param_values);
       if (handler == NULL) {
         // Check for an embedder handler.
         EmbedderServiceHandler* e_handler =
@@ -3138,9 +2559,8 @@
         if (e_handler != NULL) {
           EmbedderHandleMessage(e_handler, &js);
         } else {
-          if (FindIsolateMessageHandlerNew(method.ToCString()) != NULL) {
-            PrintError(&js, "%s expects an 'isolate' parameter\n",
-                       method.ToCString());
+          if (FindIsolateMessageHandler(method.ToCString()) != NULL) {
+            PrintMissingParamError(&js, "isolateId");
           } else {
             PrintError(&js, "Unrecognized method: %s", method.ToCString());
           }
@@ -3158,84 +2578,6 @@
 }
 
 
-void Service::HandleRootMessage(const Instance& msg) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(!msg.IsNull());
-  ASSERT(msg.IsArray());
-
-  {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
-
-    const Array& message = Array::Cast(msg);
-    // Message is a list with five entries.
-    ASSERT(message.Length() == 5);
-
-    Object& tmp = Object::Handle(isolate);
-    tmp = message.At(2);
-    if (tmp.IsString()) {
-      return Service::HandleRootMessageNew(message);
-    }
-
-    Instance& reply_port = Instance::Handle(isolate);
-    GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
-    Array& option_keys = Array::Handle(isolate);
-    Array& option_values = Array::Handle(isolate);
-
-    reply_port ^= message.At(1);
-    path ^= message.At(2);
-    option_keys ^= message.At(3);
-    option_values ^= message.At(4);
-
-    ASSERT(!path.IsNull());
-    ASSERT(!option_keys.IsNull());
-    ASSERT(!option_values.IsNull());
-    // Path always has at least one entry in it.
-    ASSERT(path.Length() > 0);
-    // Same number of option keys as values.
-    ASSERT(option_keys.Length() == option_values.Length());
-
-    if (!reply_port.IsSendPort()) {
-      FATAL("SendPort expected.");
-    }
-
-    String& path_segment = String::Handle();
-    if (path.Length() > 0) {
-      path_segment ^= path.At(0);
-    } else {
-      path_segment ^= Symbols::Empty().raw();
-    }
-    ASSERT(!path_segment.IsNull());
-    const char* path_segment_c = path_segment.ToCString();
-
-    RootMessageHandler handler =
-        FindRootMessageHandler(path_segment_c);
-    {
-      JSONStream js;
-      js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
-               path, option_keys, option_values);
-      if (handler == NULL) {
-        // Check for an embedder handler.
-        EmbedderServiceHandler* e_handler =
-            FindRootEmbedderHandler(path_segment_c);
-        if (e_handler != NULL) {
-          EmbedderHandleMessage(e_handler, &js);
-        } else {
-          PrintError(&js, "Unrecognized path");
-        }
-        js.PostReply();
-      } else {
-        if (handler(&js)) {
-          // Handler returns true if the reply is ready to be posted.
-          // TODO(johnmccutchan): Support asynchronous replies.
-          js.PostReply();
-        }
-      }
-    }
-  }
-}
-
-
 static bool HandleRootEcho(JSONStream* js) {
   JSONObject jsobj(js);
   return HandleCommonEcho(&jsobj, js);
@@ -3293,83 +2635,59 @@
 }
 
 
-static bool HandleFlags(JSONStream* js) {
-  if (js->num_arguments() == 1) {
-    Flags::PrintJSON(js);
-    return true;
-  } else if (js->num_arguments() == 2) {
-    const char* arg = js->GetArgument(1);
-    if (strcmp(arg, "set") == 0) {
-      if (js->num_arguments() > 2) {
-        PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
-                   js->num_arguments());
-      } else {
-        if (js->HasOption("name") && js->HasOption("value")) {
-          JSONObject jsobj(js);
-          const char* flag_name = js->LookupOption("name");
-          const char* flag_value = js->LookupOption("value");
-          const char* error = NULL;
-          if (Flags::SetFlag(flag_name, flag_value, &error)) {
-            jsobj.AddProperty("type", "Success");
-            jsobj.AddProperty("id", "");
-          } else {
-            jsobj.AddProperty("type", "Failure");
-            jsobj.AddProperty("id", "");
-            jsobj.AddProperty("message", error);
-          }
-        } else {
-          PrintError(js, "expected to find 'name' and 'value' options");
-        }
-      }
-    }
-    return true;
-  } else {
-    PrintError(js, "Command too long");
-    return true;
-  }
+static bool HandleVMFlagList(JSONStream* js) {
+  Flags::PrintJSON(js);
+  return true;
 }
 
-static RootMessageHandlerEntry root_handlers[] = {
-  { "vm", HandleVM },
-  { "flags", HandleFlags },
-};
 
-
-static RootMessageHandler FindRootMessageHandler(const char* command) {
-  intptr_t num_message_handlers = sizeof(root_handlers) /
-                                  sizeof(root_handlers[0]);
-  for (intptr_t i = 0; i < num_message_handlers; i++) {
-    const RootMessageHandlerEntry& entry = root_handlers[i];
-    if (strcmp(command, entry.command) == 0) {
-      return entry.handler;
-    }
+static bool HandleVMSetFlag(JSONStream* js) {
+  const char* flag_name = js->LookupParam("name");
+  if (flag_name == NULL) {
+    PrintMissingParamError(js, "name");
+    return true;
   }
-  if (FLAG_trace_service) {
-    OS::Print("vm-service: No root message handler for <%s>.\n", command);
+  const char* flag_value = js->LookupParam("value");
+  if (flag_value == NULL) {
+    PrintMissingParamError(js, "value");
+    return true;
   }
-  return NULL;
+  JSONObject jsobj(js);
+  const char* error = NULL;
+  if (Flags::SetFlag(flag_name, flag_value, &error)) {
+    jsobj.AddProperty("type", "Success");
+    jsobj.AddProperty("id", "");
+    return true;
+  } else {
+    jsobj.AddProperty("type", "Failure");
+    jsobj.AddProperty("id", "");
+    jsobj.AddProperty("message", error);
+    return true;
+  }
 }
 
 
 static RootMessageHandlerEntry root_handlers_new[] = {
   { "getVM", HandleVM },
+  { "getFlagList", HandleVMFlagList },
+  { "setFlag", HandleVMSetFlag },
   { "getVMMetricList", HandleVMGetMetricList },
   { "getVMMetric", HandleVMGetMetric },
   { "_echo", HandleRootEcho },
 };
 
 
-static RootMessageHandler FindRootMessageHandlerNew(const char* command) {
+static RootMessageHandler FindRootMessageHandler(const char* method) {
   intptr_t num_message_handlers = sizeof(root_handlers_new) /
                                   sizeof(root_handlers_new[0]);
   for (intptr_t i = 0; i < num_message_handlers; i++) {
     const RootMessageHandlerEntry& entry = root_handlers_new[i];
-    if (strcmp(command, entry.command) == 0) {
+    if (strcmp(method, entry.method) == 0) {
       return entry.handler;
     }
   }
   if (FLAG_trace_service) {
-    OS::Print("vm-service: No root message handler for <%s>.\n", command);
+    OS::Print("vm-service: No root message handler for <%s>.\n", method);
   }
   return NULL;
 }
@@ -3456,12 +2774,10 @@
   Dart_ServiceRequestCallback callback = handler->callback();
   ASSERT(callback != NULL);
   const char* r = NULL;
-  const char* name = js->command();
-  const char** arguments = js->arguments();
-  const char** keys = js->option_keys();
-  const char** values = js->option_values();
-  r = callback(name, arguments, js->num_arguments(), keys, values,
-               js->num_options(), handler->user_data());
+  const char* name = js->method();
+  const char** keys = js->param_keys();
+  const char** values = js->param_values();
+  r = callback(name, keys, values, js->num_params(), handler->user_data());
   ASSERT(r != NULL);
   // TODO(johnmccutchan): Allow for NULL returns?
   TextBuffer* buffer = js->buffer();
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 2816173..2af9b2d 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -29,11 +29,9 @@
   static bool IsServiceIsolateName(const char* name);
 
   // Handles a message which is not directed to an isolate.
-  static void HandleRootMessageNew(const Array& message);
   static void HandleRootMessage(const Instance& message);
 
   // Handles a message which is directed to a particular isolate.
-  static void HandleIsolateMessageNew(Isolate* isolate, const Array& message);
   static void HandleIsolateMessage(Isolate* isolate, const Array& message);
 
   static Isolate* GetServiceIsolate(void* callback_data);
diff --git a/runtime/vm/service/message.dart b/runtime/vm/service/message.dart
index 4b2f80a..011d57d 100644
--- a/runtime/vm/service/message.dart
+++ b/runtime/vm/service/message.dart
@@ -10,8 +10,6 @@
   /// Future of response.
   Future<String> get response => _completer.future;
 
-  final bool isOld;
-
   // In new messages.
   final String method;
 
@@ -32,29 +30,10 @@
     });
   }
 
-  Message.fromUri(Uri uri) : isOld = true {
-    var split = uri.path.split('/');
-    if (split.length == 0) {
-      setErrorResponse('Invalid uri: $uri.');
-      return;
-    }
-    _setPath(split);
-    params.addAll(uri.queryParameters);
-  }
-
-  Message.fromJsonRpc(this.method, Map rpcParams)
-      : isOld = false {
+  Message.fromJsonRpc(this.method, Map rpcParams) {
     params.addAll(rpcParams);
   }
 
-  Message.fromMap(Map map) : isOld = true {
-    _setPath(map['path']);
-    // TODO - turnidge - change this to params in sender.
-    if (map['options'] != null) {
-      params.addAll(map['options']);
-    }
-  }
-
   dynamic toJson() {
     return {
       'path': path,
@@ -94,7 +73,7 @@
     var request = new List(5)
         ..[0] = 0  // Make room for OOB message type.
         ..[1] = receivePort.sendPort
-        ..[2] = (isOld ? path : method)
+        ..[2] = method
         ..[3] = keys
         ..[4] = values;
     sendIsolateServiceMessage(sendPort, request);
@@ -116,7 +95,7 @@
     var request = new List(5)
         ..[0] = 0  // Make room for OOB message type.
         ..[1] = receivePort.sendPort
-        ..[2] = (isOld ? path : method)
+        ..[2] = method
         ..[3] = keys
         ..[4] = values;
     sendRootServiceMessage(request);
diff --git a/runtime/vm/service/running_isolates.dart b/runtime/vm/service/running_isolates.dart
index 124eb90..7766491 100644
--- a/runtime/vm/service/running_isolates.dart
+++ b/runtime/vm/service/running_isolates.dart
@@ -26,11 +26,7 @@
   }
 
   Future<String> route(Message message) {
-    if (message.isOld) {
-      return routeOld(message);
-    }
-
-    String isolateParam = message.params['isolate'];
+    String isolateParam = message.params['isolateId'];
     int isolateId;
     if (!isolateParam.startsWith('isolates/')) {
       message.setErrorResponse('Malformed isolate id $isolateParam');
@@ -54,39 +50,4 @@
     }
     return isolate.route(message);
   }
-
-  Future<String> routeOld(Message message) {
-    if (message.path.length == 0) {
-      message.setErrorResponse('No path.');
-      return message.response;
-    }
-    if (message.path[0] != 'isolates') {
-      message.setErrorResponse('Path must begin with /isolates/');
-      return message.response;
-    }
-    if (message.path.length < 2) {
-      message.setErrorResponse('An isolate id must be provided');
-      return message.response;
-    }
-    var isolateId;
-    if ((message.path[1] == 'root') && (_rootPortId != null)) {
-      isolateId = _rootPortId;
-    } else {
-      try {
-        isolateId = int.parse(message.path[1]);
-      } catch (e) {
-        message.setErrorResponse('Could not parse isolate id: $e');
-        return message.response;
-      }
-    }
-    assert(isolateId != null);
-    var isolate = isolates[isolateId];
-    if (isolate == null) {
-      message.setErrorResponse('Cannot find isolate id: $isolateId');
-      return message.response;
-    }
-    // Consume '/isolates/isolateId'
-    message.path.removeRange(0, 2);
-    return isolate.route(message);
-  }
 }
diff --git a/runtime/vm/service/service.idl b/runtime/vm/service/service.idl
index e915378..0edb79b 100644
--- a/runtime/vm/service/service.idl
+++ b/runtime/vm/service/service.idl
@@ -3,6 +3,17 @@
 //
 
 interface Service {
+  getVM() VM
+
+  getFlagList() FlagList
+
+  setFlag(name string, value string) Response
+
+  getObject(isolateId string, objectId string) Object
+
+  // The response is a subtype of Object or ObjectRef.
+  getObjectByAddress(address string, ref bool) Response
+
   // Returns the list of breakpoints for an isolate.
   getBreakpoints(isolateId string) BreakpointList
 
@@ -127,6 +138,16 @@
 }
 
 
+struct VM extends Response {
+  placeholder int
+}
+
+
+struct FlagList extends Response {
+  placeholder int
+}
+
+
 struct _EchoResponse extends Response {
   text string
 }
diff --git a/runtime/vm/service/vmservice.dart b/runtime/vm/service/vmservice.dart
index 3c5ed24..d4eca93 100644
--- a/runtime/vm/service/vmservice.dart
+++ b/runtime/vm/service/vmservice.dart
@@ -138,18 +138,13 @@
     if (message.completed) {
       return message.response;
     }
+    // TODO(turnidge): Update to json rpc.  BEFORE SUBMIT.
     if ((message.path.length == 1) && (message.path[0] == 'clients')) {
       _clientCollection(message);
       return message.response;
     }
-    if (message.isOld) {
-      if (message.path[0] == 'isolates') {
-        return runningIsolates.route(message);
-      }
-    } else {
-      if (message.params['isolate'] != null) {
-        return runningIsolates.route(message);
-      }
+    if (message.params['isolateId'] != null) {
+      return runningIsolates.route(message);
     }
     return message.sendToVM();
   }
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index ee6659a..17691b4 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -184,7 +184,7 @@
   Array& service_msg = Array::Handle();
 
   // Get the isolate summary.
-  service_msg = Eval(lib, "[0, port, [], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getIsolate', [], []]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
 
@@ -248,7 +248,8 @@
   Array& service_msg = Array::Handle();
 
   // null
-  service_msg = Eval(lib, "[0, port, ['objects', 'null'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', "
+                     "['objectId'], ['objects/null']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   handler.filterMsg("_vmName");
@@ -257,59 +258,9 @@
       "\"valueAsString\":\"null\",\"class\":",
       handler.msg());
 
-  // not initialized
-  service_msg = Eval(lib, "[0, port, ['objects', 'not-initialized'], [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  handler.filterMsg("_vmName");
-  EXPECT_STREQ(
-      "{\"type\":\"Sentinel\",\"id\":\"objects\\/not-initialized\","
-      "\"valueAsString\":\"<not initialized>\"}",
-      handler.msg());
-
-  // being initialized
-  service_msg = Eval(lib,
-                     "[0, port, ['objects', 'being-initialized'], [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  handler.filterMsg("_vmName");
-  EXPECT_STREQ(
-      "{\"type\":\"Sentinel\",\"id\":\"objects\\/being-initialized\","
-      "\"valueAsString\":\"<being initialized>\"}",
-      handler.msg());
-
-  // optimized out
-  service_msg = Eval(lib, "[0, port, ['objects', 'optimized-out'], [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  handler.filterMsg("_vmName");
-  EXPECT_STREQ(
-      "{\"type\":\"Sentinel\",\"id\":\"objects\\/optimized-out\","
-      "\"valueAsString\":\"<optimized out>\"}",
-      handler.msg());
-
-  // collected
-  service_msg = Eval(lib, "[0, port, ['objects', 'collected'], [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  handler.filterMsg("_vmName");
-  EXPECT_STREQ(
-      "{\"type\":\"Sentinel\",\"id\":\"objects\\/collected\","
-      "\"valueAsString\":\"<collected>\"}",
-      handler.msg());
-
-  // expired
-  service_msg = Eval(lib, "[0, port, ['objects', 'expired'], [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  handler.filterMsg("_vmName");
-  EXPECT_STREQ(
-      "{\"type\":\"Sentinel\",\"id\":\"objects\\/expired\","
-      "\"valueAsString\":\"<expired>\"}",
-      handler.msg());
-
   // bool
-  service_msg = Eval(lib, "[0, port, ['objects', 'bool-true'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', "
+                     "['objectId'], ['objects/bool-true']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   handler.filterMsg("_vmName");
@@ -323,7 +274,8 @@
       handler.msg());
 
   // int
-  service_msg = Eval(lib, "[0, port, ['objects', 'int-123'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', "
+                     "['objectId'], ['objects/int-123']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   handler.filterMsg("_vmName");
@@ -337,7 +289,8 @@
       handler.msg());
 
   // object id ring / valid
-  service_msg = Eval(lib, "[0, port, ['objects', '$validId'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', "
+                     "['objectId'], ['objects/$validId']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   handler.filterMsg("_vmName");
@@ -356,7 +309,8 @@
       handler.msg());
 
   // object id ring / invalid => expired
-  service_msg = Eval(lib, "[0, port, ['objects', '99999999'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', "
+                     "['objectId'], ['objects/99999999']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   handler.filterMsg("_vmName");
@@ -541,9 +495,10 @@
   Array& service_msg = Array::Handle();
 
   // Request library.
-  service_msg = EvalF(lib,
-                      "[0, port, ['libraries', '%" Pd "'], [], []]",
-                      vmlib.index());
+  service_msg =
+      EvalF(lib,
+            "[0, port, 'getObject', ['objectId'], ['libraries/%" Pd "']]",
+            vmlib.index());
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Library\"", handler.msg());
@@ -594,17 +549,15 @@
   Array& service_msg = Array::Handle();
 
   // Request an invalid class id.
-  service_msg = Eval(lib, "[0, port, ['classes', '999999'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', "
+                     "['objectId'], ['classes/999999']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
-    "{\"type\":\"Error\","
-    "\"message\":\"999999 is not a valid class id.\","
-    "\"request\":{\"arguments\":[\"classes\",\"999999\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Request the class A over the service.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "'], [], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
@@ -616,8 +569,8 @@
 
   // Request function 'b' from class A.
   service_msg = EvalF(lib,
-                      "[0, port, ['classes', '%" Pd "', 'functions', 'b'],"
-                      "[], []]", cid);
+                      "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/functions/b']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Function\"", handler.msg());
@@ -626,8 +579,8 @@
                    "\"name\":\"b\",", cid);
 
   // Request field 0 from class A.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'fields', '0'],"
-                      "[], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/fields/0']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Field\"", handler.msg());
@@ -636,74 +589,51 @@
                    "\"name\":\"a\",", cid);
 
   // Invalid sub command.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'huh', '0'],"
-                      "[], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/huh']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\",\"message\":\"Invalid sub collection huh\""
-    ",\"request\":"
-    "{\"arguments\":[\"classes\",\"%" Pd "\",\"huh\",\"0\"],\"option_keys\":[],"
-    "\"option_values\":[]}}", cid);
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Invalid field request.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'fields', '9'],"
-                      "[], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/fields/9']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\",\"message\":\"Field 9 not found\","
-    "\"request\":{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", cid);
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Invalid function request.
   service_msg = EvalF(lib,
-                      "[0, port, ['classes', '%" Pd "', 'functions', '9'],"
-                      "[], []]", cid);
+                      "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/functions/9']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\",\"message\":\"Function 9 not found\","
-    "\"request\":{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"9\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", cid);
-
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Invalid field subcommand.
   service_msg = EvalF(lib,
-                      "[0, port, ['classes', '%" Pd "', 'fields', '9', 'x']"
-                      ",[], []]", cid);
+                      "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/fields/9']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\",\"message\":\"Command too long\","
-    "\"request\":"
-    "{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\",\"x\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", cid);
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Invalid function command.
   service_msg = EvalF(lib,
-                      "[0, port, ['classes', '%" Pd "', 'functions', '0',"
-                      "'x', 'y'], [], []]", cid);
+                      "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/functions/0/x/y']]",
+                      cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\","
-    "\"message\":\"Command should have 4 or 5 arguments\","
-    "\"request\":"
-    "{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"0\",\"x\",\"y\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", cid);
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Invalid function subcommand with valid function id.
   service_msg = EvalF(lib,
-                      "[0, port, ['classes', '%" Pd "', 'functions', 'b',"
-                      "'x'], [], []]", cid);
+                      "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/functions/b/x']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\",\"message\":\"Invalid sub command x\","
-    "\"request\":"
-    "{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"b\",\"x\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", cid);
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Retained size of all instances of class B.
   const Class& class_b = Class::Handle(GetClass(vmlib, "B"));
@@ -748,127 +678,6 @@
 }
 
 
-TEST_CASE(Service_SetSource) {
-  const char* kScript =
-      "var port;\n"  // Set to our mock port by C++.
-      "\n"
-      "class A {\n"
-      "  a() { return 1; }\n"
-      "  b() { return 0; }\n"
-      "  c(String f) { return f.length; }\n"
-      "}\n"
-      "main() {\n"
-      "  var z = new A();\n"
-      "  return z.a();\n"
-      "}\n"
-      "runB() {\n"
-      "  var z = new A();\n"
-      "  return z.b();\n"
-      "}\n"
-      "runC() {\n"
-      "  var z = new A();\n"
-      "  return z.c();\n"
-      "}\n";
-
-  Isolate* isolate = Isolate::Current();
-  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
-  EXPECT_VALID(lib);
-  Library& vmlib = Library::Handle();
-  vmlib ^= Api::UnwrapHandle(lib);
-  EXPECT(!vmlib.IsNull());
-  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
-  EXPECT_VALID(result);
-  const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
-  EXPECT(!class_a.IsNull());
-  intptr_t cid = class_a.id();
-
-  // Build a mock message handler and wrap it in a dart port.
-  ServiceTestMessageHandler handler;
-  Dart_Port port_id = PortMap::CreatePort(&handler);
-  Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
-  EXPECT_VALID(port);
-  EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
-
-  Array& service_msg = Array::Handle();
-
-  // Request the class A over the service.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "'], [], []]", cid);
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
-  ExpectSubstringF(handler.msg(),
-                   "\"id\":\"classes\\/%" Pd "\",\"name\":\"A\",", cid);
-  ExpectSubstringF(handler.msg(), "\"allocationStats\":");
-  ExpectSubstringF(handler.msg(), "\"tokenPos\":");
-  ExpectSubstringF(handler.msg(), "\"endTokenPos\":");
-
-  // Request function 'b' from class A.
-  service_msg = EvalF(lib,
-                      "[0, port, ['classes', '%" Pd "', 'functions', 'b'],"
-                      "[], []]", cid);
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  EXPECT_SUBSTRING("\"type\":\"Function\"", handler.msg());
-  ExpectSubstringF(handler.msg(),
-                   "\"id\":\"classes\\/%" Pd "\\/functions\\/b\","
-                   "\"name\":\"b\",", cid);
-
-  // Invalid set source of function 'b' from class A.
-  service_msg = EvalF(
-    lib,
-    "[0, port, ['classes', '%" Pd "', 'functions', 'b', 'set_source'],"
-    "[], []]", cid);
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
-  EXPECT_SUBSTRING("set_source expects a 'source' option", handler.msg());
-
-  // Set source (with syntax error) of function 'b' from class A.
-  service_msg = EvalF(
-    lib,
-    "[0, port, ['classes', '%" Pd "', 'functions', 'b', 'set_source'],"
-    "['source'], ['b() { return 4 }']]", cid);
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
-
-  // Set source of function 'b' from class A.
-  service_msg = EvalF(
-    lib,
-    "[0, port, ['classes', '%" Pd "', 'functions', 'b', 'set_source'],"
-    "['source'], ['b() { return 4; }']]", cid);
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  EXPECT_SUBSTRING("Success", handler.msg());
-
-  // Run function 'b' see that it is executing replaced code.
-  result = Dart_Invoke(lib, NewString("runB"), 0, NULL);
-  EXPECT_VALID(result);
-  ASSERT(Dart_IsInteger(result));
-  int64_t r;
-  result = Dart_IntegerToInt64(result, &r);
-  EXPECT_VALID(result);
-  EXPECT_EQ(4, r);
-
-  // Set source of function 'c' from class A, changing its signature.
-  service_msg = EvalF(
-    lib,
-    "[0, port, ['classes', '%" Pd "', 'functions', 'c', 'set_source'],"
-    "['source'], ['c() { return 99; }']]", cid);
-  Service::HandleIsolateMessage(isolate, service_msg);
-  handler.HandleNextMessage();
-  EXPECT_SUBSTRING("Success", handler.msg());
-
-  // Run function 'c' see that it is executing replaced code.
-  result = Dart_Invoke(lib, NewString("runC"), 0, NULL);
-  EXPECT_VALID(result);
-  ASSERT(Dart_IsInteger(result));
-  result = Dart_IntegerToInt64(result, &r);
-  EXPECT_VALID(result);
-  EXPECT_EQ(99, r);
-}
-
-
 TEST_CASE(Service_Types) {
   const char* kScript =
       "var port;\n"  // Set to our mock port by C++.
@@ -901,7 +710,8 @@
   Array& service_msg = Array::Handle();
 
   // Request the class A over the service.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "'], [], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "']]]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
@@ -910,8 +720,8 @@
                    "\"id\":\"classes\\/%" Pd "\"", cid);
 
   // Request canonical type 0 from class A.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'types', '0'],"
-                              "[], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/types/0']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Type\"", handler.msg());
@@ -920,8 +730,8 @@
                    "\"id\":\"classes\\/%" Pd "\\/types\\/0\"", cid);
 
   // Request canonical type 1 from class A.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'types', '1'],"
-                              "[], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/types/1']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("\"type\":\"Type\"", handler.msg());
@@ -930,16 +740,11 @@
                    "\"id\":\"classes\\/%" Pd "\\/types\\/1\"", cid);
 
   // Request for non-existent canonical type from class A.
-  service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'types', '42'],"
-                      "[], []]", cid);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['classes/%" Pd "/types/42']]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  ExpectSubstringF(handler.msg(),
-    "{\"type\":\"Error\","
-    "\"message\":\"Canonical type 42 not found\""
-    ",\"request\":"
-    "{\"arguments\":[\"classes\",\"%" Pd "\",\"types\",\"42\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", cid);
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 }
 
 
@@ -991,17 +796,15 @@
   Array& service_msg = Array::Handle();
 
   // Request an invalid code object.
-  service_msg = Eval(lib, "[0, port, ['code', '0'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObject', ['objectId'], ['code/0']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
-    "{\"type\":\"Error\",\"message\":\"Malformed code id: 0\","
-    "\"request\":{\"arguments\":[\"code\",\"0\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // The following test checks that a code object can be found only
   // at compile_timestamp()-code.EntryPoint().
-  service_msg = EvalF(lib, "[0, port, ['code', '%" Px64"-%" Px "'], [], []]",
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['code/%" Px64"-%" Px "']]",
                       compile_timestamp,
                       entry);
   Service::HandleIsolateMessage(isolate, service_msg);
@@ -1020,44 +823,29 @@
   // Request code object at compile_timestamp-code.EntryPoint() + 16
   // Expect this to fail because the address is not the entry point.
   uintptr_t address = entry + 16;
-  service_msg = EvalF(lib, "[0, port, ['code', '%" Px64"-%" Px "'], [], []]",
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['code/%" Px64"-%" Px "']]",
                       compile_timestamp,
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  {
-    // Only perform a partial match.
-    const intptr_t kBufferSize = 512;
-    char buffer[kBufferSize];
-    OS::SNPrint(buffer, kBufferSize-1,
-                "Could not find code with id: %" Px64 "-%" Px "",
-                compile_timestamp,
-                address);
-    EXPECT_SUBSTRING(buffer, handler.msg());
-  }
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Request code object at (compile_timestamp - 1)-code.EntryPoint()
   // Expect this to fail because the timestamp is wrong.
   address = entry;
-  service_msg = EvalF(lib, "[0, port, ['code', '%" Px64"-%" Px "'], [], []]",
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['code/%" Px64"-%" Px "']]",
                       compile_timestamp - 1,
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  {
-    // Only perform a partial match.
-    const intptr_t kBufferSize = 512;
-    char buffer[kBufferSize];
-    OS::SNPrint(buffer, kBufferSize-1,
-                "Could not find code with id: %" Px64 "-%" Px "",
-                compile_timestamp - 1,
-                address);
-    EXPECT_SUBSTRING(buffer, handler.msg());
-  }
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 
   // Request native code at address. Expect the null code object back.
   address = last;
-  service_msg = EvalF(lib, "[0, port, ['code', 'native-%" Px "'], [], []]",
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['code/native-%" Px "']]",
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
@@ -1066,11 +854,12 @@
                    handler.msg());
 
   // Request malformed native code.
-  service_msg = EvalF(lib, "[0, port, ['code', 'native%" Px "'], [], []]",
+  service_msg = EvalF(lib, "[0, port, 'getObject', ['objectId'], "
+                      "['code/native%" Px "']]",
                       address);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_SUBSTRING("\"message\":\"Malformed code id:", handler.msg());
+  EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
 }
 
 
@@ -1109,7 +898,8 @@
   Array& service_msg = Array::Handle();
 
   // Fetch object.
-  service_msg = EvalF(lib, "[0, port, ['objects', '%" Pd "'], [], []]", id);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['objects/%" Pd "']]", id);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
 
@@ -1170,7 +960,8 @@
   Array& service_msg = Array::Handle();
 
   // Fetch object.
-  service_msg = EvalF(lib, "[0, port, ['objects', '%" Pd "'], [], []]", id);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['objects/%" Pd "']]", id);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   // Check type.
@@ -1230,7 +1021,8 @@
   Array& service_msg = Array::Handle();
 
   // Fetch object.
-  service_msg = EvalF(lib, "[0, port, ['objects', '%" Pd "'], [], []]", id);
+  service_msg = EvalF(lib, "[0, port, 'getObject', "
+                      "['objectId'], ['objects/%" Pd "']]", id);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   // Check type.
@@ -1260,7 +1052,7 @@
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
   Array& service_msg = Array::Handle();
-  service_msg = Eval(lib, "[0, port, ['vm'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getVM', [], []]");
 
   Service::HandleRootMessage(service_msg);
   handler.HandleNextMessage();
@@ -1292,7 +1084,7 @@
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
   Array& service_msg = Array::Handle();
-  service_msg = Eval(lib, "[0, port, ['flags'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getFlagList', [], []]");
 
   // Make sure we can get the FlagList.
   Service::HandleRootMessage(service_msg);
@@ -1305,14 +1097,14 @@
 
   // Modify a flag through the vm service.
   service_msg = Eval(lib,
-                     "[0, port, ['flags', 'set'], "
+                     "[0, port, 'setFlag', "
                      "['name', 'value'], ['service_testing_flag', 'true']]");
   Service::HandleRootMessage(service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING("Success", handler.msg());
 
   // Make sure that the flag changed.
-  service_msg = Eval(lib, "[0, port, ['flags'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getFlagList', [], []]");
   Service::HandleRootMessage(service_msg);
   handler.HandleNextMessage();
   EXPECT_SUBSTRING(
@@ -1346,8 +1138,9 @@
   Array& service_msg = Array::Handle();
   char buf[1024];
   OS::SNPrint(buf, sizeof(buf),
-      "[0, port, ['libraries', '%" Pd "', 'scripts', 'test-lib'], [], []]",
-      vmlib.index());
+              "[0, port, 'getObject', "
+              "['objectId'], ['libraries/%" Pd "/scripts/test-lib']]",
+              vmlib.index());
 
   service_msg = Eval(lib, buf);
   Service::HandleIsolateMessage(isolate, service_msg);
@@ -1490,8 +1283,11 @@
     char buf[1024];
     bool ref = offset % 2 == 0;
     OS::SNPrint(buf, sizeof(buf),
-                ref ? "[0, port, ['address', '%" Px "'], ['ref'], ['true']]" :
-                      "[0, port, ['address', '%" Px "', ], [], []]",
+                (ref
+                 ? "[0, port, 'getObjectByAddress', "
+                   "['address', 'ref'], ['%" Px "', 'true']]"
+                 : "[0, port, 'getObjectByAddress', "
+                   "['address'], ['%" Px "']]"),
                 addr);
     service_msg = Eval(lib, buf);
     Service::HandleIsolateMessage(isolate, service_msg);
@@ -1502,7 +1298,8 @@
     EXPECT_SUBSTRING("foobar", handler.msg());
   }
   // Expect null when no object is found.
-  service_msg = Eval(lib, "[0, port, ['address', '7'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'getObjectByAddress', "
+                     "['address'], ['7']]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   // TODO(turnidge): Should this be a ServiceException instead?
@@ -1514,8 +1311,6 @@
 
 static const char* alpha_callback(
     const char* name,
-    const char** arguments,
-    intptr_t num_arguments,
     const char** option_keys,
     const char** option_values,
     intptr_t num_options,
@@ -1526,8 +1321,6 @@
 
 static const char* beta_callback(
     const char* name,
-    const char** arguments,
-    intptr_t num_arguments,
     const char** option_keys,
     const char** option_values,
     intptr_t num_options,
@@ -1564,11 +1357,11 @@
 
 
   Array& service_msg = Array::Handle();
-  service_msg = Eval(lib, "[0, port, ['alpha'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'alpha', [], []]");
   Service::HandleRootMessage(service_msg);
   handler.HandleNextMessage();
   EXPECT_STREQ("alpha", handler.msg());
-  service_msg = Eval(lib, "[0, port, ['beta'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'beta', [], []]");
   Service::HandleRootMessage(service_msg);
   handler.HandleNextMessage();
   EXPECT_STREQ("beta", handler.msg());
@@ -1601,11 +1394,11 @@
   EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
 
   Array& service_msg = Array::Handle();
-  service_msg = Eval(lib, "[0, port, ['alpha'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'alpha', [], []]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_STREQ("alpha", handler.msg());
-  service_msg = Eval(lib, "[0, port, ['beta'], [], []]");
+  service_msg = Eval(lib, "[0, port, 'beta', [], []]");
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
   EXPECT_STREQ("beta", handler.msg());
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 73e0b18..90a1b41 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -37,8 +37,13 @@
   V(Call, "call")                                                              \
   V(Current, "current")                                                        \
   V(MoveNext, "moveNext")                                                      \
+  V(IsYieldEach, "isYieldEach")                                                \
   V(Value, "value")                                                            \
   V(_EnumHelper, "_EnumHelper")                                                \
+  V(_SyncIterable, "_SyncIterable")                                            \
+  V(_SyncIterableConstructor, "_SyncIterable.")                                \
+  V(_SyncIterator, "_SyncIterator")                                            \
+  V(IteratorParameter, ":iterator")                                            \
   V(Values, "values")                                                          \
   V(_EnumNames, "_enum_names")                                                 \
   V(ExprTemp, ":expr_temp")                                                    \
@@ -66,7 +71,7 @@
   V(StringBase, "_StringBase")                                                 \
   V(Interpolate, "_interpolate")                                               \
   V(InterpolateSingle, "_interpolateSingle")                                   \
-  V(GetIterator, "iterator")                                                   \
+  V(Iterator, "iterator")                                                      \
   V(NoSuchMethod, "noSuchMethod")                                              \
   V(CurrentContextVar, ":current_context_var")                                 \
   V(SavedTryContextVar, ":saved_try_context_var")                              \
@@ -80,6 +85,8 @@
   V(LoadLibrary, "loadLibrary")                                                \
   V(_LibraryPrefix, "_LibraryPrefix")                                          \
   V(Async, "async")                                                            \
+  V(Sync, "sync")                                                              \
+  V(YieldKw, "yield")                                                          \
   V(AsyncCompleter, ":async_completer")                                        \
   V(AsyncOperation, ":async_op")                                               \
   V(AsyncOperationParam, ":async_result")                                      \
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index 7a75198..f89fe9d 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -1829,7 +1829,7 @@
   _StackTrace(this._exception);
 
   String toString() {
-    if (_trace != null) return _trace;
+    if (_trace != null) return JS('String', '#', _trace);
 
     String trace;
     if (JS('bool', 'typeof # === "object"', _exception)) {
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
index 35740f0..dead76f 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
@@ -25,7 +25,7 @@
 final _validOptions = new Set<String>.from([
   'commandLineOptions', 'checked', 'csp', 'minify', 'verbose', 'environment',
   'preserveUris', 'suppressWarnings', 'suppressHints',
-  'suppressPackageWarnings', 'terse'
+  'suppressPackageWarnings', 'terse', 'sourceMaps'
 ]);
 
 /// A [Transformer] that uses dart2js's library API to transform Dart
@@ -42,7 +42,8 @@
   final BarbackSettings _settings;
 
   /// Whether source maps should be generated for the compiled JS.
-  bool get _generateSourceMaps => _settings.mode != BarbackMode.RELEASE;
+  bool get _generateSourceMaps => _configBool('sourceMaps',
+      defaultsTo: _settings.mode != BarbackMode.RELEASE);
 
   Dart2JSTransformer.withSettings(this._environment, this._settings) {
     var invalidOptions = _settings.configuration.keys.toSet()
@@ -146,7 +147,7 @@
         suppressPackageWarnings: _configBool(
             'suppressPackageWarnings', defaultsTo: true),
         terse: _configBool('terse'),
-        includeSourceMapUrls: _settings.mode != BarbackMode.RELEASE);
+        includeSourceMapUrls: _generateSourceMaps);
   }
 
   /// Parses and returns the "commandLineOptions" configuration option.
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 449c482..f2be2f2 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -6,6 +6,11 @@
 test/serve/web_socket/url_to_asset_id_test: Pass, Slow
 test/transformer/loads_a_diamond_transformer_dependency_graph_test: Pass, Slow
 
+test/global/binstubs/outdated_binstub_runs_pub_global_test: Fail  # 22284
+test/global/binstubs/outdated_snapshot_test: Fail  # 22284
+test/global/run/recompiles_if_sdk_is_out_of_date_test: Fail  # 22284
+test/snapshot/recompiles_if_the_sdk_is_out_of_date_test: Fail  # 22284
+
 # Pub only runs on the VM, so just rule out all compilers.
 [ $compiler == dart2js || $compiler == dart2dart ]
 *: Skip
diff --git a/sdk/lib/_internal/pub/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart b/sdk/lib/_internal/pub/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
new file mode 100644
index 0000000..7efba1d
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+  initConfig();
+  integration("includes source maps in a release build if sourceMaps true", () {
+    d.dir(appPath, [
+      d.pubspec({
+        'name': 'myapp',
+        'transformers': [{
+          '\$dart2js': {
+            'sourceMaps': true
+          }
+        }]
+      }),
+      d.dir("web", [
+        d.file("main.dart", "void main() => print('hello');")
+      ])
+    ]).create();
+
+    schedulePub(args: ["build"],
+        output: new RegExp(r'Built \d+ files to "build".'),
+        exitCode: 0);
+
+    d.dir(appPath, [
+      d.dir('build', [
+        d.dir('web', [
+          d.matcherFile('main.dart.js',
+              contains("# sourceMappingURL=main.dart.js.map")),
+          d.matcherFile('main.dart.js.map', contains('"file": "main.dart.js"'))
+        ])
+      ])
+    ]).validate();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart b/sdk/lib/_internal/pub/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
new file mode 100644
index 0000000..aaecf9b
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+  initConfig();
+  integration("omits source maps from a debug build if sourceMaps false", () {
+    d.dir(appPath, [
+      d.pubspec({
+        'name': 'myapp',
+        'transformers': [{
+          '\$dart2js': {
+            'sourceMaps': false
+          }
+        }]
+      }),
+      d.dir("web", [
+        d.file("main.dart", "void main() => print('hello');")
+      ])
+    ]).create();
+
+    schedulePub(args: ["build", "--mode", "debug"],
+        output: new RegExp(r'Built \d+ files to "build".'),
+        exitCode: 0);
+
+    d.dir(appPath, [
+      d.dir('build', [
+        d.dir('web', [
+          d.nothing('main.dart.js.map')
+        ])
+      ])
+    ]).validate();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart b/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart
index 81212b0..2cd9deb 100644
--- a/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart
+++ b/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart
@@ -25,7 +25,8 @@
             "suppressWarnings": true,
             "suppressHints": true,
             "suppressPackageWarnings": false,
-            "terse": true
+            "terse": true,
+            "sourceMaps": false
           }
         }]
       }),
diff --git a/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart
index 3910ef8..b6362eb 100644
--- a/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart
@@ -33,7 +33,8 @@
         'suppressWarnings',
         'suppressHints',
         'suppressPackageWarnings',
-        'terse']);
+        'terse',
+        'sourceMaps']);
 
 /// A [Transformer] that uses dart2js's library API to transform Dart
 /// entrypoints in "web" to JavaScript.
@@ -49,7 +50,8 @@
   final BarbackSettings _settings;
 
   /// Whether source maps should be generated for the compiled JS.
-  bool get _generateSourceMaps => _settings.mode != BarbackMode.RELEASE;
+  bool get _generateSourceMaps =>
+      _configBool('sourceMaps', defaultsTo: _settings.mode != BarbackMode.RELEASE);
 
   Dart2JSTransformer.withSettings(this._environment, this._settings) {
     var invalidOptions =
@@ -158,7 +160,7 @@
             'suppressPackageWarnings',
             defaultsTo: true),
         terse: _configBool('terse'),
-        includeSourceMapUrls: _settings.mode != BarbackMode.RELEASE);
+        includeSourceMapUrls: _generateSourceMaps);
   }
 
   /// Parses and returns the "commandLineOptions" configuration option.
diff --git a/sdk/lib/_internal/pub_generated/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart b/sdk/lib/_internal/pub_generated/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
new file mode 100644
index 0000000..f8ebaec
--- /dev/null
+++ b/sdk/lib/_internal/pub_generated/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+  initConfig();
+  integration("includes source maps in a release build if sourceMaps true", () {
+    d.dir(appPath, [d.pubspec({
+        'name': 'myapp',
+        'transformers': [{
+            '\$dart2js': {
+              'sourceMaps': true
+            }
+          }]
+      }),
+          d.dir(
+              "web",
+              [d.file("main.dart", "void main() => print('hello');")])]).create();
+
+    schedulePub(
+        args: ["build"],
+        output: new RegExp(r'Built \d+ files to "build".'),
+        exitCode: 0);
+
+    d.dir(
+        appPath,
+        [
+            d.dir(
+                'build',
+                [
+                    d.dir(
+                        'web',
+                        [
+                            d.matcherFile('main.dart.js', contains("# sourceMappingURL=main.dart.js.map")),
+                            d.matcherFile(
+                                'main.dart.js.map',
+                                contains('"file": "main.dart.js"'))])])]).validate();
+  });
+}
diff --git a/sdk/lib/_internal/pub_generated/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart b/sdk/lib/_internal/pub_generated/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
new file mode 100644
index 0000000..f777b91
--- /dev/null
+++ b/sdk/lib/_internal/pub_generated/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+  initConfig();
+  integration("omits source maps from a debug build if sourceMaps false", () {
+    d.dir(appPath, [d.pubspec({
+        'name': 'myapp',
+        'transformers': [{
+            '\$dart2js': {
+              'sourceMaps': false
+            }
+          }]
+      }),
+          d.dir(
+              "web",
+              [d.file("main.dart", "void main() => print('hello');")])]).create();
+
+    schedulePub(
+        args: ["build", "--mode", "debug"],
+        output: new RegExp(r'Built \d+ files to "build".'),
+        exitCode: 0);
+
+    d.dir(
+        appPath,
+        [d.dir('build', [d.dir('web', [d.nothing('main.dart.js.map')])])]).validate();
+  });
+}
diff --git a/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart b/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart
index 07afaa9..1c43421 100644
--- a/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart
+++ b/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart
@@ -26,7 +26,8 @@
               "suppressWarnings": true,
               "suppressHints": true,
               "suppressPackageWarnings": false,
-              "terse": true
+              "terse": true,
+              "sourceMaps": false
             }
           }]
       }),
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index d22f5ba..de9af01 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -43,7 +43,7 @@
 
   AsyncError(this.error, this.stackTrace);
 
-  String toString() => error.toString();
+  String toString() => '$error';
 }
 
 
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 793c36c..d93583c 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -146,7 +146,7 @@
   @DocsEditable()
   Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
 }
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2015, 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.
 
@@ -247,9 +247,10 @@
   @Experimental() // untriaged
   String username;
 
+
   @DomName('HTMLAnchorElement.toString')
   @DocsEditable()
-  String toString() native;
+  String toString() => JS('String', 'String(#)', this);
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -707,7 +708,7 @@
   @Experimental() // untriaged
   final String url;
 }
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2015, 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.
 
@@ -804,10 +805,10 @@
   @Experimental() // untriaged
   String username;
 
+
   @DomName('HTMLAreaElement.toString')
   @DocsEditable()
-  @Experimental() // untriaged
-  String toString() native;
+  String toString() => JS('String', 'String(#)', this);
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -8576,8 +8577,7 @@
 
   @DomName('DOMException.toString')
   @DocsEditable()
-  String toString() native;
-
+  String toString() => JS('String', 'String(#)', this);
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -11095,7 +11095,9 @@
 
   @DomName('Element.localName')
   @DocsEditable()
-  String get localName => _localName;
+  @Returns('String')
+  // Non-null for Elements.
+  String get localName => JS('String', '#', _localName);
 
   /**
    * A URI that identifies the XML namespace of this element.
@@ -19006,10 +19008,6 @@
   @DocsEditable()
   void replace(String url) native;
 
-  @DomName('Location.toString')
-  @DocsEditable()
-  String toString() native;
-
 
   @DomName('Location.origin')
   String get origin {
@@ -19018,6 +19016,10 @@
     }
     return '${this.protocol}//${this.host}';
   }
+
+  @DomName('Location.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -21926,7 +21928,10 @@
   /**
    * Print out a String representation of this Node.
    */
-  String toString() => nodeValue == null ? super.toString() : nodeValue;
+  String toString() {
+    String value = nodeValue;  // Fetch DOM Node property once.
+    return value == null ? super.toString() : value;
+  }
   // To suppress missing implicit constructor warnings.
   factory Node._() { throw new UnsupportedError("Not supported"); }
 
@@ -28896,6 +28901,11 @@
   static void revokeObjectUrl(String url) =>
       JS('void',
          '(self.URL || self.webkitURL).revokeObjectURL(#)', url);
+
+  @DomName('URL.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
+
   // To suppress missing implicit constructor warnings.
   factory Url._() { throw new UnsupportedError("Not supported"); }
 
@@ -28956,11 +28966,6 @@
   @Experimental() // untriaged
   String username;
 
-  @DomName('URL.toString')
-  @DocsEditable()
-  @Experimental() // untriaged
-  String toString() native;
-
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 1504658..b195b1a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -20860,6 +20860,7 @@
   String toString() => _blink.BlinkLocation.instance.toString_Callback_0_(this);
 
 
+
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -23993,7 +23994,10 @@
   /**
    * Print out a String representation of this Node.
    */
-  String toString() => nodeValue == null ? super.toString() : nodeValue;
+  String toString() {
+    String value = nodeValue;  // Fetch DOM Node property once.
+    return value == null ? super.toString() : value;
+  }
   // To suppress missing implicit constructor warnings.
   factory Node._() { throw new UnsupportedError("Not supported"); }
 
@@ -31432,10 +31436,10 @@
     if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaStream)) {
+    if ((blob_OR_source_OR_stream is MediaSource)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaSource)) {
+    if ((blob_OR_source_OR_stream is MediaStream)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
     }
     throw new ArgumentError("Incorrect number or type of arguments");
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 711793a..8a493a2 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -729,7 +729,7 @@
    * *NOTE* file locking does have slight differences in behavior across
    * platforms:
    *
-   * On Linux and Mac OS this uses advisory locks, which have the
+   * On Linux and OS X this uses advisory locks, which have the
    * surprising semantics that all locks associated with a given file
    * are removed when *any* file descriptor for that file is closed by
    * the process. Note that this does not actually lock the file for
@@ -762,7 +762,7 @@
    * *NOTE* file locking does have slight differences in behavior across
    * platforms:
    *
-   * On Linux and Mac OS this uses advisory locks, which have the
+   * On Linux and OS X this uses advisory locks, which have the
    * surprising semantics that all locks associated with a given file
    * are removed when *any* file descriptor for that file is closed by
    * the process. Note that this does not actually lock the file for
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index f392327..642a063 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -273,7 +273,7 @@
    *
    * [resolveSymbolicLinks] uses the operating system's native
    * file system API to resolve the path, using the `realpath` function
-   * on linux and Mac OS, and the `GetFinalPathNameByHandle` function on
+   * on linux and OS X, and the `GetFinalPathNameByHandle` function on
    * Windows. If the path does not point to an existing file system object,
    * `resolveSymbolicLinks` throws a `FileSystemException`.
    *
@@ -313,7 +313,7 @@
    *
    * [resolveSymbolicLinksSync] uses the operating system's native
    * file system API to resolve the path, using the `realpath` function
-   * on linux and Mac OS, and the `GetFinalPathNameByHandle` function on
+   * on linux and OS X, and the `GetFinalPathNameByHandle` function on
    * Windows. If the path does not point to an existing file system object,
    * `resolveSymbolicLinksSync` throws a `FileSystemException`.
    *
@@ -418,7 +418,7 @@
    *     files and directories. Recursive watching is not supported.
    *     Note: When watching files directly, delete events might not happen
    *     as expected.
-   *   * `Mac OS`: Uses `FSEvents`. The implementation supports watching both
+   *   * `OS X`: Uses `FSEvents`. The implementation supports watching both
    *     files and directories. Recursive watching is supported.
    *
    * The system will start listening for events once the returned [Stream] is
@@ -529,7 +529,7 @@
   /**
    * Test if [watch] is supported on the current system.
    *
-   * Mac OS 10.6 and below is not supported.
+   * OS X 10.6 and below is not supported.
    */
   static bool get isWatchSupported => _FileSystemWatcher.isSupported;
 
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index b90afe4..12e152c 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -100,7 +100,7 @@
   static final bool isLinux = (_operatingSystem == "linux");
 
   /**
-   * Returns true if the operating system is Mac OS.
+   * Returns true if the operating system is OS X.
    */
   static final bool isMacOS = (_operatingSystem == "macos");
 
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 43f6bcd..2d8ecab 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -23,7 +23,7 @@
  *
  * The handling of exit codes is platform specific.
  *
- * On Linux and Mac OS an exit code for normal termination will always
+ * On Linux and OS X an exit code for normal termination will always
  * be in the range [0..255]. If an exit code outside this range is
  * set the actual exit code will be the lower 8 bits masked off and
  * treated as an unsigned value. E.g. using an exit code of -1 will
@@ -212,7 +212,7 @@
    *
    * The handling of exit codes is platform specific.
    *
-   * On Linux and Mac a normal exit code will be a positive value in
+   * On Linux and OS X a normal exit code will be a positive value in
    * the range [0..255]. If the process was terminated due to a signal
    * the exit code will be a negative value in the range [-255..-1],
    * where the absolute value of the exit code is the signal
@@ -255,7 +255,7 @@
    * precedence. Default is `true`.
    *
    * If [runInShell] is `true`, the process will be spawned through a system
-   * shell. On Linux and Mac OS, [:/bin/sh:] is used, while
+   * shell. On Linux and OS X, [:/bin/sh:] is used, while
    * [:%WINDIR%\system32\cmd.exe:] is used on Windows.
    *
    * Users must read all data coming on the [stdout] and [stderr]
@@ -320,7 +320,7 @@
    * precedence. Default is `true`.
    *
    * If [runInShell] is true, the process will be spawned through a system
-   * shell. On Linux and Mac OS, `/bin/sh` is used, while
+   * shell. On Linux and OS X, `/bin/sh` is used, while
    * `%WINDIR%\system32\cmd.exe` is used on Windows.
    *
    * The encoding used for decoding `stdout` and `stderr` into text is
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index d9c713f..42e1478 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -2957,6 +2957,11 @@
 LayoutTests/fast/alignment/parse-align-items_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/alignment/parse-align-self_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/alignment/parse-justify-self_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-cancel2_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-cancel_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-timestamps-advance_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-timestamps_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-within-callback_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/backgrounds/background-repeat-computed-style_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/backgrounds/repeat/parsing-background-repeat_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/borders/border-image-width-numbers-computed-style_t01: RuntimeError # Please triage this failure
@@ -2968,6 +2973,7 @@
 LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.verySmall_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/alpha_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-arc-negative-radius_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/canvas-as-image-incremental-repaint_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/canvas/canvas-blend-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blend-solid_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-blending-clipping_t01: RuntimeError # Please triage this failure
@@ -3021,6 +3027,7 @@
 LayoutTests/fast/canvas/drawImage-with-broken-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/drawImage-with-valid-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/getPutImageDataPairTest_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/setWidthResetAfterForcedRender_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/array-bounds-clamping_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: RuntimeError # Please triage this failure
@@ -3099,7 +3106,7 @@
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgb565_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # Please triage this failure
@@ -3332,6 +3339,7 @@
 LayoutTests/fast/dom/HTMLScriptElement/async-onbeforeload_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLScriptElement/defer-inline-script_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLScriptElement/defer-onbeforeload_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/HTMLScriptElement/script-set-src_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLSelectElement/selected-index-preserved-when-option-text-changes_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLTemplateElement/custom-element-wrapper-gc_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLTemplateElement/cycles-in-shadow_t01: RuntimeError # Please triage this failure
@@ -3408,6 +3416,7 @@
 LayoutTests/fast/dom/implementation-api-args_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/implementation-createHTMLDocument_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/importNode-unsupported-node-type_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/location-hash_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/dom/location-missing-arguments_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/navigatorcontentutils/is-protocol-handler-registered_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/navigatorcontentutils/register-protocol-handler_t01: RuntimeError # Please triage this failure
@@ -3512,6 +3521,7 @@
 LayoutTests/fast/events/invalid-004_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/events/mutation-during-replace-child-2_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/events/mutation-during-replace-child_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/events/overflowchanged-event-raf-timing_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/events/scroll-event-does-not-bubble_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/events/tabindex-removal-from-focused-element_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/events/wheelevent-constructor_t01: RuntimeError # Please triage this failure
@@ -3524,6 +3534,7 @@
 LayoutTests/fast/files/blob-parts-slice-test_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/files/blob-slice-test_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/files/file-reader-abort-in-last-progress_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/files/file-reader-done-reading-abort_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/files/file-reader-methods-illegal-arguments_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/files/file-reader-readystate_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/files/url-null_t01: RuntimeError # Please triage this failure
@@ -3704,8 +3715,10 @@
 LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-different-writing-modes-right_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/shapes/shape-outside-floats/shape-outside-rounded-boxes_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/shapes/shape-outside-floats/shape-outside-rounded-boxes_t02: RuntimeError # Please triage this failure
+LayoutTests/fast/speechsynthesis/speech-synthesis-boundary-events_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/speechsynthesis/speech-synthesis-cancel_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/speechsynthesis/speech-synthesis-pause-resume_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/speechsynthesis/speech-synthesis-speak_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/speechsynthesis/speech-synthesis-utterance-uses-voice_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/speechsynthesis/speech-synthesis-voices_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/storage/disallowed-storage_t01: RuntimeError # Please triage this failure
@@ -3918,6 +3931,7 @@
 LibTest/html/Node/nodes_A01_t02: RuntimeError # Please triage this failure
 LibTest/html/Node/parent_A01_t01: RuntimeError # Please triage this failure
 LibTest/html/Node/previousNode_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Window/animationFrame_A01_t01: Skip # Times out. Please triage this failure
 LibTest/html/Window/close_A01_t01: RuntimeError # Please triage this failure
 LibTest/html/Window/document_A01_t01: RuntimeError # Please triage this failure
 LibTest/html/Window/find_A01_t01: RuntimeError # Please triage this failure
@@ -3931,7 +3945,7 @@
 LibTest/html/Window/requestFileSystem_A01_t01: RuntimeError # Please triage this failure
 LibTest/html/Window/requestFileSystem_A01_t02: RuntimeError # Please triage this failure
 LibTest/html/Window/requestFileSystem_A02_t01: RuntimeError # Please triage this failure
-LibTest/html/Window/resizeBy_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Window/resizeBy_A01_t01: Skip # Times out. Please triage this failure
 LibTest/html/Window/resizeTo_A01_t01: RuntimeError # Please triage this failure
 LibTest/typed_data/Float32x4List/Float32x4List.view_A06_t01: RuntimeError # Please triage this failure
 LibTest/typed_data/Int32x4/operator_OR_A01_t01: RuntimeError # Please triage this failure
@@ -4190,9 +4204,10 @@
 WebPlatformTest/webstorage/event_local_key_t01: RuntimeError # Please triage this failure
 WebPlatformTest/webstorage/event_session_key_t01: RuntimeError # Please triage this failure
 WebPlatformTest/webstorage/event_session_storagearea_t01: Pass, RuntimeError # Fails on 7.1. Please triage this failure
+WebPlatformTest/webstorage/event_session_url_t01: Skip # Times out. Please triage this failure
 WebPlatformTest/webstorage/storage_local_setitem_t01: RuntimeError # Please triage this failure
 WebPlatformTest/webstorage/storage_session_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure
-WebPlatformTest/webstorage/storage_session_setitem_t01: RuntimeError # Please triage this failure
+WebPlatformTest/webstorage/storage_session_setitem_t01: Skip # Times out. Please triage this failure
 
 [ $compiler == dart2js && $runtime == safarimobilesim ]
 Language/12_Expressions/00_Object_Identity/1_Object_Identity_A05_t02: RuntimeError # Please triage this failure
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 4e39fdf..5607f3f 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -2,9 +2,10 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-async_await_syntax_test: Fail # Issue 22260
 boolified_operator_test: Fail # Issue 8001
 
+async_await_syntax_test: Skip # Not sure how/why test cases a03b, a04c fail.
+
 # simple_function_subtype_test is temporarily(?) disabled due to new method for
 # building function type tests.
 simple_function_subtype_test: Fail
diff --git a/tests/compiler/dart2js/expect_annotations_test.dart b/tests/compiler/dart2js/expect_annotations_test.dart
new file mode 100644
index 0000000..ed8889a
--- /dev/null
+++ b/tests/compiler/dart2js/expect_annotations_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/dart2jslib.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/js_backend/js_backend.dart';
+import 'memory_compiler.dart';
+
+const Map MEMORY_SOURCE_FILES = const {
+  'main.dart': r"""
+import 'package:expect/expect.dart';
+
+int method(String arg) => arg.length;
+
+@AssumeDynamic()
+int methodAssumeDynamic(String arg) => arg.length;
+
+@TrustTypeAnnotations()
+int methodTrustTypeAnnotations(String arg) => arg.length;
+
+@NoInlining()
+int methodNoInlining(String arg) => arg.length;
+
+@NoInlining() @TrustTypeAnnotations()
+int methodNoInliningTrustTypeAnnotations(String arg) => arg.length;
+
+void main(List<String> args) {
+  print(method(args[0]));
+  print(methodAssumeDynamic('foo'));
+  print(methodTrustTypeAnnotations(null));
+  print(methodNoInlining('bar'));
+  print(methodNoInliningTrustTypeAnnotations(null));
+}
+"""
+};
+
+main() {
+  Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
+  asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+    Expect.isFalse(compiler.compilationFailed, 'Unsuccessful compilation');
+    JavaScriptBackend backend = compiler.backend;
+    Expect.isNotNull(backend.annotations.expectNoInliningClass,
+        'NoInliningClass is unresolved.');
+    Expect.isNotNull(backend.annotations.expectTrustTypeAnnotationsClass,
+        'TrustTypeAnnotations is unresolved.');
+    Expect.isNotNull(backend.annotations.expectAssumeDynamicClass,
+        'AssumeDynamicClass is unresolved.');
+
+    void test(String name,
+              {bool expectNoInlining: false,
+               bool expectTrustTypeAnnotations: false,
+               bool expectAssumeDynamic: false}) {
+       Element method = compiler.mainApp.find(name);
+       Expect.isNotNull(method);
+       Expect.equals(
+           expectNoInlining,
+           backend.annotations.noInlining(method),
+           "Unexpected annotation of @NoInlining on '$method'.");
+       Expect.equals(
+           expectTrustTypeAnnotations,
+           backend.annotations.trustTypeAnnotations(method),
+           "Unexpected annotation of @TrustTypeAnnotations on '$method'.");
+       Expect.equals(
+           expectAssumeDynamic,
+           backend.annotations.assumeDynamic(method),
+           "Unexpected annotation of @AssumeDynamic on '$method'.");
+    }
+
+    test('method');
+    test('methodAssumeDynamic', expectAssumeDynamic: true);
+    test('methodTrustTypeAnnotations', expectTrustTypeAnnotations: true);
+    test('methodNoInlining', expectNoInlining: true);
+    test('methodNoInliningTrustTypeAnnotations',
+         expectNoInlining: true,
+         expectTrustTypeAnnotations: true);
+  }));
+}
diff --git a/tests/language/async_await_syntax_test.dart b/tests/language/async_await_syntax_test.dart
index 3c8c38b..b1affb9 100644
--- a/tests/language/async_await_syntax_test.dart
+++ b/tests/language/async_await_syntax_test.dart
@@ -15,10 +15,10 @@
 a01c() sync* => null;                        /// a01c: compile-time error
 a02a() async {}                              /// a02a: ok
 a03a() async* {}                             /// a03a: ok
-a03b() async * {}                            /// a03b: compile-time error
+a03b() async * {}                            /// a03b: ok
 a04a() sync* {}                              /// a04a: ok
 a04b() sync {}                               /// a04b: compile-time error
-a04c() sync * {}                             /// a04c: compile-time error
+a04c() sync * {}                             /// a04c: ok
 a05a() async { await 0; }                    /// a05a: ok
 a05b() async {                               /// a05b: ok
   await(a) {};                               /// a05b: continued
diff --git a/tests/language/cyclic_type_test.dart b/tests/language/cyclic_type_test.dart
index 4de75d9..ed591fc 100644
--- a/tests/language/cyclic_type_test.dart
+++ b/tests/language/cyclic_type_test.dart
@@ -28,6 +28,11 @@
 class Derived2<V> extends Base<Derived1<Derived2<V>>> {}   /// 04: ok
 
 main() {
+  // In the tests below we test that we get "int" and "bool" when calling
+  // toString() on the int and bool type respectively. This is not required
+  // behavior. However, we want to keep the original names for the most common
+  // core types so we make sure to handle these specifically in the compiler.
+
   var d;
   d = new Derived();  /// 00: continued
   Expect.equals("Derived", d.t.toString());  /// 00: continued
@@ -37,6 +42,7 @@
   Expect.equals("Derived<Derived>", d.t.toString());  /// 00: continued
 
   d = new Derived();  /// 01: continued
+
   Expect.equals("Derived<Derived<int>>", d.t.toString());  /// 01: continued
   d = new Derived<bool>();  /// 01: continued
   Expect.equals("Derived<Derived<int>>", d.t.toString());  /// 01: continued
diff --git a/tests/language/f_bounded_quantification5_test.dart b/tests/language/f_bounded_quantification5_test.dart
index b45cb2d..b70f061 100644
--- a/tests/language/f_bounded_quantification5_test.dart
+++ b/tests/language/f_bounded_quantification5_test.dart
@@ -25,6 +25,9 @@
 main() {
   bool got_type_error = false;
   try {
+    // Getting "int" when calling toString() on the int type is not required.
+    // However, we want to keep the original names for the most common core
+    // types so we make sure to handle these specifically in the compiler.
     Expect.equals("A<B<int>>", new A<B<int>>().runtimeType.toString());
   } on TypeError catch (error) {
     got_type_error = true;
diff --git a/tests/language/language.status b/tests/language/language.status
index e87eb35..acad979 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -7,7 +7,6 @@
 
 [ $compiler == none ]
 built_in_identifier_prefix_test: Fail # Issue 6970
-async_await_syntax_test/b00a: MissingCompileTimeError # Issue 21404
 
 # These bugs refer currently ongoing language discussions.
 constructor_initializer_test/none: Fail # Issue 12633
@@ -19,6 +18,7 @@
 duplicate_export_negative_test: Fail # Issue 6134
 
 [ $compiler == dart2dart ]
+
 deferred_load_library_wrong_args_test/none: Fail # Issue 17523
 deferred_load_inval_code_test: Fail # Issue 17523
 deferred_not_loaded_check_test: Fail # Issue 17523
@@ -41,68 +41,39 @@
 least_upper_bound_expansive_test/*: Fail, OK
 
 compile_time_constant12_test: Fail # Issue 21000
-async_await_syntax_test/a07a: CompileTimeError # Issue 21404
-async_await_syntax_test/a08a: CompileTimeError # Issue 21404
 async_await_syntax_test/a09a: CompileTimeError # Issue 21404
 async_await_syntax_test/a10a: CompileTimeError # Issue 21404
-async_await_syntax_test/b07a: CompileTimeError # Issue 21404
-async_await_syntax_test/b08a: CompileTimeError # Issue 21404
 async_await_syntax_test/b09a: CompileTimeError # Issue 21404
 async_await_syntax_test/b10a: CompileTimeError # Issue 21404
-async_await_syntax_test/c07a: CompileTimeError # Issue 21404
-async_await_syntax_test/c08a: CompileTimeError # Issue 21404
 async_await_syntax_test/c09a: CompileTimeError # Issue 21404
 async_await_syntax_test/c10a: CompileTimeError # Issue 21404
-async_await_syntax_test/d07a: CompileTimeError # Issue 21404
-async_await_syntax_test/d08a: CompileTimeError # Issue 21404
-async_await_syntax_test/d08b: CompileTimeError # Issue 21404
 async_await_syntax_test/d09a: CompileTimeError # Issue 21404
 async_await_syntax_test/d10a: CompileTimeError # Issue 21404
 
 [ $compiler == none || ($compiler == dart2dart && $builder_tag != new_backend) ]
 compile_time_constant_c_test/01: Fail # Issue 21000
 async_await_syntax_test/a03a: CompileTimeError # Issue 21404
-async_await_syntax_test/a04a: CompileTimeError # Issue 21404
-async_await_syntax_test/a11b: CompileTimeError # Issue 21404
+async_await_syntax_test/a03b: CompileTimeError # Issue 21404
 async_await_syntax_test/a11d: CompileTimeError # Issue 21404
 async_await_syntax_test/b03a: CompileTimeError # Issue 21404
-async_await_syntax_test/b04a: CompileTimeError # Issue 21404
-async_await_syntax_test/b11b: CompileTimeError # Issue 21404
 async_await_syntax_test/b11d: CompileTimeError # Issue 21404
 async_await_syntax_test/c03a: CompileTimeError # Issue 21404
-async_await_syntax_test/c04a: CompileTimeError # Issue 21404
 async_await_syntax_test/d03a: CompileTimeError # Issue 21404
-async_await_syntax_test/d04a: CompileTimeError # Issue 21404
 
 [ $compiler == none && ($runtime == drt || $runtime == dartium|| $runtime == ContentShellOnAndroid) ]
 async_await_syntax_test/a03a: RuntimeError # Issue 21404
-async_await_syntax_test/a04a: RuntimeError # Issue 21404
-async_await_syntax_test/a07a: RuntimeError # Issue 21404
-async_await_syntax_test/a08a: RuntimeError # Issue 21404
+async_await_syntax_test/a03b: RuntimeError # Issue 21404
 async_await_syntax_test/a09a: RuntimeError # Issue 21404
 async_await_syntax_test/a10a: RuntimeError # Issue 21404
-async_await_syntax_test/a11b: RuntimeError # Issue 21404
 async_await_syntax_test/a11d: RuntimeError # Issue 21404
-async_await_syntax_test/b00a: Fail  # Issue 21404
 async_await_syntax_test/b03a: RuntimeError # Issue 21404
-async_await_syntax_test/b04a: RuntimeError # Issue 21404
-async_await_syntax_test/b07a: RuntimeError # Issue 21404
-async_await_syntax_test/b08a: RuntimeError # Issue 21404
 async_await_syntax_test/b09a: RuntimeError # Issue 21404
 async_await_syntax_test/b10a: RuntimeError # Issue 21404
-async_await_syntax_test/b11b: RuntimeError # Issue 21404
 async_await_syntax_test/b11d: RuntimeError # Issue 21404
 async_await_syntax_test/c03a: RuntimeError # Issue 21404
-async_await_syntax_test/c04a: RuntimeError # Issue 21404
-async_await_syntax_test/c07a: RuntimeError # Issue 21404
-async_await_syntax_test/c08a: RuntimeError # Issue 21404
 async_await_syntax_test/c09a: RuntimeError # Issue 21404
 async_await_syntax_test/c10a: RuntimeError # Issue 21404
 async_await_syntax_test/d03a: RuntimeError # Issue 21404
-async_await_syntax_test/d04a: RuntimeError # Issue 21404
-async_await_syntax_test/d07a: RuntimeError # Issue 21404
-async_await_syntax_test/d08a: RuntimeError # Issue 21404
-async_await_syntax_test/d08b: RuntimeError # Issue 21404
 async_await_syntax_test/d09a: RuntimeError # Issue 21404
 async_await_syntax_test/d10a: RuntimeError # Issue 21404
 
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 242a521..ffee566 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -6,12 +6,12 @@
 await_backwards_compatibility_test/none: CompileTimeError # Issue 22052
 await_test: CompileTimeError # Issue 22052
 
+sync_generator2_test: Skip #
+
 async_test/type-mismatch2: MissingStaticWarning # Issue 22053
 async_test/type-mismatch3: MissingStaticWarning # Issue 22053
 async_test/type-mismatch4: MissingStaticWarning # Issue 22053
 
-async_await_syntax_test/a03b: MissingCompileTimeError # Issue 22234
-async_await_syntax_test/a04c: MissingCompileTimeError # Issue 22234
 async_await_syntax_test/a05c: CompileTimeError
 async_await_syntax_test/a05e: CompileTimeError
 async_await_syntax_test/a05f: MissingCompileTimeError
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 793472d..b0c7bfd 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -4,9 +4,6 @@
 
 [ $compiler == dart2analyzer ]
 
-async_await_syntax_test/a03b: MissingCompileTimeError # Issue 22234
-async_await_syntax_test/a04c: MissingCompileTimeError # Issue 22234
-
 # Runtime negative test. No static errors or warnings.
 closure_call_wrong_argument_count_negative_test: skip
 
@@ -16,6 +13,8 @@
 enum_syntax_test/05: Fail # 21649
 enum_syntax_test/06: Fail # 21649
 
+sync_generator1_test: Fail
+
 compile_time_constant_c_test/01: Fail # Issue 21000
 compile_time_constant12_test: Fail # Issue 21000
 
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index fd18821..9a0121e 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -15,6 +15,8 @@
 await_nonfuture_test: CompileTimeError # Issue 21411
 await_regression_test: CompileTimeError # Issue 21411
 await_test: CompileTimeError # Issue 21411
+sync_generator1_test: Fail # Issue 21411
+sync_generator2_test/none: Fail # Issue 21411
 async_await_syntax_test/a01a: CompileTimeError # Issue 21411
 async_await_syntax_test/a02a: CompileTimeError # Issue 21411
 async_await_syntax_test/a03a: CompileTimeError # Issue 21411
@@ -63,6 +65,9 @@
 async_await_syntax_test/d08b: CompileTimeError # Issue 21411
 async_await_syntax_test/d09a: CompileTimeError # Issue 21411
 async_await_syntax_test/d10a: CompileTimeError # Issue 21411
+async_await_syntax_test/a04c: CompileTimeError # Issue 22259
+async_await_syntax_test/a03b: CompileTimeError # Issue 22259
+
 
 [ $compiler == dart2js && $unchecked ]
 async_test/type-mismatch1: CompileTimeError # Issue 21411
@@ -269,6 +274,16 @@
 type_variable_conflict2_test/01: RuntimeError # Issue 16180
 
 [ $compiler == dart2dart ]
+async_await_syntax_test/a04c: Fail
+async_await_syntax_test/a03b: Fail
+sync_generator2_test/07: Fail
+sync_generator2_test/08: Fail
+sync_generator2_test/10: Fail
+sync_generator2_test/20: Fail
+sync_generator2_test/30: Fail
+sync_generator2_test/51: Fail
+sync_generator2_test/52: Fail
+
 regress_13494_test: Fail # Issue 13494
 
 enum_duplicate_test/01: CompileTimeError # Issue 22169
@@ -322,6 +337,8 @@
 function_subtype_call2_test: RuntimeError # Issue 21673
 
 [ $compiler == dart2dart && $minified ]
+sync_generator1_test: Fail
+sync_generator2_test/none: Fail
 cyclic_type_test/0*: Fail # Issue 12605.
 cyclic_type2_test: Fail # Issue 12605.
 super_getter_setter_test: Fail # Issue 11065.
diff --git a/tests/language/mixin_type_parameters_simple_test.dart b/tests/language/mixin_type_parameters_simple_test.dart
index 0df7996..c077cab 100644
--- a/tests/language/mixin_type_parameters_simple_test.dart
+++ b/tests/language/mixin_type_parameters_simple_test.dart
@@ -18,6 +18,9 @@
 
 main() {
   var a = new A<int>();
+  // Getting "int" when calling toString() on the int type is not required.
+  // However, we want to keep the original names for the most common core types
+  // so we make sure to handle these specifically in the compiler.
   Expect.equals("int", a.m1().toString());
   Expect.equals("int", a.m2().toString());
   a = new A<String>();
diff --git a/tests/language/sync_generator1_test.dart b/tests/language/sync_generator1_test.dart
new file mode 100644
index 0000000..8da1a88
--- /dev/null
+++ b/tests/language/sync_generator1_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2015, 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.
+
+// Simple test program for sync* generator functions.
+
+// VMOptions=--optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+sum10() sync* {
+  var s = 0;
+  for (var k = 1; k <= 10; k++) {
+    s += k;
+    yield s;
+  }
+}
+
+class Range {
+  int start, end;
+  Range(this.start, this.end);
+  elements() sync* {
+    var e = start;
+    while (e <= end) yield e++;
+  }
+
+  get yield sync* {  // yield is a legal member name here.
+    var e = start;
+    while (e <= end) yield e++;
+  }
+}
+
+get sync sync* {  // sync is a legal identifier.
+  yield "sync";
+}
+
+einsZwei() sync* {
+  yield* 1;
+  yield* [2, 3];
+  yield* [];
+  yield 5;
+  yield [6];
+}
+
+main() {
+  for (int i = 0; i < 10; i++) {
+    var sums = sum10();
+    print(sums);
+    Expect.isTrue(sums is Iterable);
+    Expect.equals(10, sums.length);
+    Expect.equals(1, sums.first);
+    Expect.equals(55, sums.last);
+    var q = "";
+    for (var n in sums.take(3)) {
+      q += "$n ";
+    }
+    Expect.equals("1 3 6 ", q);
+
+    var r = new Range(10, 12);
+    var elems1 = r.elements();
+    print(elems1);
+    var elems2 = r.yield;
+    print(elems2);
+    // Walk the elements of each iterable and compare them.
+    var i = elems1.iterator;
+    Expect.isTrue(i is Iterator);
+    elems2.forEach((e) {
+      Expect.isTrue(i.moveNext());
+      Expect.equals(e, i.current);
+    });
+
+    print(sync);
+    Expect.equals("sync", sync.single);
+
+    print(einsZwei());
+    Expect.equals("(1, 2, 3, 5, [6])", einsZwei().toString());
+  }
+}
diff --git a/tests/language/sync_generator2_test.dart b/tests/language/sync_generator2_test.dart
new file mode 100644
index 0000000..ca6920c
--- /dev/null
+++ b/tests/language/sync_generator2_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2015, 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.
+
+// Simple test program for sync* generator functions.
+
+import "package:expect/expect.dart";
+import "dart:async";
+
+var sync = "topLevelSync";
+var async = "topLevelAync";
+var await = "topLevelAwait";
+var yield = "topLevelYield";
+
+test01() sync* {
+  var yield = 0;  /// 01: compile-time error
+  var await = 0;  /// 02: compile-time error
+  var async = 0;  /// 03: compile-time error
+  bool yield() => false; /// 04: compile-time error
+  bool await() => false; /// 05: compile-time error
+  bool async() => false; /// 06: compile-time error
+
+  var x1 = sync;
+  var x2 = async;  /// 07: compile-time error
+  var x3 = await;  /// 08: compile-time error
+  var x4 = await 55;  /// 09: compile-time error
+  var x4 = yield;  /// 10: compile-time error
+
+  var stream = new Stream.fromIterable([1, 2, 3]);
+  await for (var e in stream) print(e);   /// 11: compile-time error
+}
+
+test02() sync* {
+  yield 12321;
+  return null;  /// 20: compile-time error
+}
+
+test03() sync* => null;   /// 30: compile-time error
+
+get test04 sync* => null;  /// 40: compile-time error
+set test04(a) sync* { print(a); }  /// 41: compile-time error
+
+class K {
+  K() sync* {};  /// 50: compile-time error
+  get nix sync* { }
+  get garnix sync* => null;  /// 51: compile-time error
+  set etwas(var z) sync* { }  /// 52: compile-time error
+  sync() sync* {
+    yield sync;  // Yields a tear-off of the sync() method.
+  }
+}
+
+main() {
+  var x;
+  x = test01();
+  Expect.equals("()", x.toString());
+  x = test02();
+  Expect.equals("(12321)", x.toString());
+  x = test04;  /// 40: continued
+  test04 = x;  /// 41: continued
+  x = new K();
+  Expect.equals(1, x.sync().length);
+  Expect.isTrue(x.sync().single is Function);
+}
\ No newline at end of file
diff --git a/tests/standalone/full_coverage_test.dart b/tests/standalone/full_coverage_test.dart
index 7bba623..04cd94e 100644
--- a/tests/standalone/full_coverage_test.dart
+++ b/tests/standalone/full_coverage_test.dart
@@ -13,7 +13,8 @@
 import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
-final String coverageScript = "tools/full-coverage.dart";
+final String coverageScript =
+    Platform.script.resolve('../../tools/full-coverage.dart').toFilePath();
 final String packageRoot = Platform.packageRoot;
 final List dartBaseArgs = ['--package-root=${packageRoot}', '--checked',];
 
diff --git a/tests/standalone/io/arguments_test.dart b/tests/standalone/io/arguments_test.dart
index 5a4ca68..a4ed16a 100644
--- a/tests/standalone/io/arguments_test.dart
+++ b/tests/standalone/io/arguments_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=tests/standalone/io/arguments_test.dart 10 arguments_test 20
+// DartOptions=10 arguments_test 20
 
 import "package:expect/expect.dart";
 
diff --git a/tests/standalone/io/directory_test.dart b/tests/standalone/io/directory_test.dart
index d06c77f..14685b1 100644
--- a/tests/standalone/io/directory_test.dart
+++ b/tests/standalone/io/directory_test.dart
@@ -124,9 +124,9 @@
   }
 
   static void testListTooLongName() {
+    asyncStart();
     Directory.systemTemp.createTemp('dart_directory').then((d) {
       var errors = 0;
-      asyncStart();
       setupListHandlers(Stream<FileSystemEntity> stream) {
         stream.listen(
           (_) => Expect.fail("Listing of non-existing directory should fail"),
diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart
index 86cb355..25cf360 100644
--- a/tests/standalone/io/file_input_stream_test.dart
+++ b/tests/standalone/io/file_input_stream_test.dart
@@ -11,8 +11,12 @@
 
 // Helper method to be able to run the test from the runtime
 // directory, or the top directory.
-String getFilename(String path) =>
-    new File(path).existsSync() ? path : '../$path';
+String getFilename(String path) {
+  var testPath = Platform.script.resolve('../../../$path');
+  return new File.fromUri(testPath).existsSync()
+      ? testPath.toFilePath()
+      : Platform.script.resolve('../../../runtime/$path').toFilePath();
+}
 
 void testStringLineSplitter() {
   String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
diff --git a/tests/standalone/io/file_invalid_arguments_test.dart b/tests/standalone/io/file_invalid_arguments_test.dart
index 58c6d7c..335e574 100644
--- a/tests/standalone/io/file_invalid_arguments_test.dart
+++ b/tests/standalone/io/file_invalid_arguments_test.dart
@@ -99,7 +99,10 @@
 }
 
 String getFilename(String path) {
-  return new File(path).existsSync() ? path : 'runtime/$path';
+  var testPath = Platform.script.resolve('../../../$path');
+  return new File.fromUri(testPath).existsSync()
+      ? testPath.toFilePath()
+      : Platform.script.resolve('../../../runtime/$path').toFilePath();
 }
 
 main() {
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index 0ce18ae..633fe38 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -969,7 +969,7 @@
     f.readAsString(encoding: UTF8).then((text) {
       Expect.isTrue(text.endsWith("42 bytes."));
       Expect.equals(42, text.length);
-      var name = getDataFilename("tests/standalone/io/read_as_text.dat");
+      var name = getFilename("tests/standalone/io/read_as_text.dat");
       var f = new File(name);
       f.readAsString(encoding: UTF8).then((text) {
         Expect.equals(6, text.length);
@@ -1006,7 +1006,7 @@
     var text = new File(name).readAsStringSync();
     Expect.isTrue(text.endsWith("42 bytes."));
     Expect.equals(42, text.length);
-    name = getDataFilename("tests/standalone/io/read_as_text.dat");
+    name = getFilename("tests/standalone/io/read_as_text.dat");
     text = new File(name).readAsStringSync();
     Expect.equals(6, text.length);
     var expected = [955, 120, 46, 32, 120, 10];
@@ -1054,7 +1054,7 @@
     var line = lines[0];
     Expect.isTrue(line.endsWith("42 bytes."));
     Expect.equals(42, line.length);
-    name = getDataFilename("tests/standalone/io/readline_test1.dat");
+    name = getFilename("tests/standalone/io/readline_test1.dat");
     lines = new File(name).readAsLinesSync();
     Expect.equals(10, lines.length);
   }
@@ -1274,11 +1274,12 @@
 
   // Helper method to be able to run the test from the runtime
   // directory, or the top directory.
-  static String getFilename(String path) =>
-      new File(path).existsSync() ? path : 'runtime/$path';
-
-  static String getDataFilename(String path) =>
-      new File(path).existsSync() ? path : '../$path';
+  static String getFilename(String path) {
+    var testPath = Platform.script.resolve('../../../$path');
+    return new File.fromUri(testPath).existsSync()
+        ? testPath.toFilePath()
+        : Platform.script.resolve('../../../runtime/$path').toFilePath();
+  }
 
   // Main test entrypoint.
   static testMain() {
diff --git a/tests/standalone/io/platform_test.dart b/tests/standalone/io/platform_test.dart
index 5abdc0f..bf59383 100644
--- a/tests/standalone/io/platform_test.dart
+++ b/tests/standalone/io/platform_test.dart
@@ -67,6 +67,8 @@
 }
 
 main() {
+  // This tests assumes paths relative to dart main directory
+  Directory.current = Platform.script.resolve('../../..').toFilePath();
   test();
   testIsolate();
 }
diff --git a/tests/standalone/io/read_into_const_list_test.dart b/tests/standalone/io/read_into_const_list_test.dart
index f010a83..3eb624a 100644
--- a/tests/standalone/io/read_into_const_list_test.dart
+++ b/tests/standalone/io/read_into_const_list_test.dart
@@ -8,8 +8,13 @@
 import "package:expect/expect.dart";
 import "dart:io";
 
-String getFilename(String path) =>
-    new File(path).existsSync() ? path : 'runtime/$path';
+String getFilename(String path) {
+  var testPath = Platform.script.resolve('../../../$path');
+  return new File.fromUri(testPath).existsSync()
+      ? testPath.toFilePath()
+      : Platform.script.resolve('../../../runtime/$path').toFilePath();
+}
+
 
 void main() {
   var a = const [0];
diff --git a/tools/VERSION b/tools/VERSION
index b1ada01..dacd602 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 9
 PATCH 0
-PRERELEASE 6
+PRERELEASE 7
 PRERELEASE_PATCH 0
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index f4bb124..91d385e 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -57,6 +57,7 @@
     'Document.createNodeIterator',
     'Document.createTreeWalker',
     'DOMException.name',
+    'DOMException.toString',
     'Element.createShadowRoot',
     'Element.insertAdjacentElement',
     'Element.insertAdjacentHTML',
@@ -67,6 +68,8 @@
     'ElementEvents.mouseWheel',
     'ElementEvents.transitionEnd',
     'FileReader.result',
+    'HTMLAnchorElement.toString',
+    'HTMLAreaElement.toString',
     'HTMLTableElement.createTBody',
     'IDBCursor.next',
     'IDBDatabase.transaction',
@@ -75,6 +78,7 @@
     'IDBDatabase.transactionStores',
     'KeyboardEvent.initKeyboardEvent',
     'Location.origin',
+    'Location.toString',
     'MouseEvent.offsetX',
     'MouseEvent.offsetY',
     'Navigator.language',
@@ -85,6 +89,7 @@
     'URL.createObjectUrlFromStream',
     'URL.createObjectUrlFromBlob',
     'URL.revokeObjectURL',
+    'URL.toString',
     'WheelEvent.deltaMode',
     'WheelEvent.wheelDeltaX',
     'WheelEvent.wheelDeltaY',
diff --git a/tools/dom/templates/html/dart2js/impl_HTMLAnchorElement.darttemplate b/tools/dom/templates/html/dart2js/impl_HTMLAnchorElement.darttemplate
new file mode 100644
index 0000000..fb6ff5f
--- /dev/null
+++ b/tools/dom/templates/html/dart2js/impl_HTMLAnchorElement.darttemplate
@@ -0,0 +1,14 @@
+// Copyright (c) 2015, 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 $LIBRARYNAME;
+
+@DocsEditable()
+$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$MIXINS$IMPLEMENTS {
+$!MEMBERS
+
+  @DomName('HTMLAnchorElement.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
+}
diff --git a/tools/dom/templates/html/dart2js/impl_HTMLAreaElement.darttemplate b/tools/dom/templates/html/dart2js/impl_HTMLAreaElement.darttemplate
new file mode 100644
index 0000000..df3fdd6
--- /dev/null
+++ b/tools/dom/templates/html/dart2js/impl_HTMLAreaElement.darttemplate
@@ -0,0 +1,14 @@
+// Copyright (c) 2015, 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 $LIBRARYNAME;
+
+@DocsEditable()
+$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$MIXINS$IMPLEMENTS {
+$!MEMBERS
+
+  @DomName('HTMLAreaElement.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
+}
diff --git a/tools/dom/templates/html/dart2js/impl_URL.darttemplate b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
index d8c8a75..1e14cca 100644
--- a/tools/dom/templates/html/dart2js/impl_URL.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
@@ -23,5 +23,10 @@
   static void revokeObjectUrl(String url) =>
       JS('void',
          '(self.URL || self.webkitURL).revokeObjectURL(#)', url);
+
+  @DomName('URL.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
+
 $!MEMBERS
 }
diff --git a/tools/dom/templates/html/impl/impl_DOMException.darttemplate b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
index db97f86..be8c36c 100644
--- a/tools/dom/templates/html/impl/impl_DOMException.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
@@ -41,4 +41,9 @@
   }
 $endif
 $!MEMBERS
+$if DART2JS
+  @DomName('DOMException.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
+$endif
 }
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index f263b29..22de38f 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -813,7 +813,13 @@
 
   @DomName('Element.localName')
   @DocsEditable()
+$if DART2JS
+  @Returns('String')
+  // Non-null for Elements.
+  String get localName => JS('String', '#', _localName);
+$else
   String get localName => _localName;
+$endif
 
   /**
    * A URI that identifies the XML namespace of this element.
diff --git a/tools/dom/templates/html/impl/impl_Location.darttemplate b/tools/dom/templates/html/impl/impl_Location.darttemplate
index d663fcd..f69d929 100644
--- a/tools/dom/templates/html/impl/impl_Location.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Location.darttemplate
@@ -17,4 +17,10 @@
     return '${this.protocol}//${this.host}';
   }
 $endif
+
+$if DART2JS
+  @DomName('Location.toString')
+  @DocsEditable()
+  String toString() => JS('String', 'String(#)', this);
+$endif
 }
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 8307149..166c346 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -272,6 +272,9 @@
   /**
    * Print out a String representation of this Node.
    */
-  String toString() => nodeValue == null ? super.toString() : nodeValue;
+  String toString() {
+    String value = nodeValue;  // Fetch DOM Node property once.
+    return value == null ? super.toString() : value;
+  }
 $!MEMBERS
 }
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 1bdf34e..1bdd0c7 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -943,8 +943,10 @@
   }
 
   bool get hasCrashed {
-    // The Java dartc runner and dart2js exits with code 253 in case
-    // of unhandled exceptions.
+    // dart2js exits with code 253 in case of unhandled exceptions.
+    // The dart binary exits with code 253 in case of an API error such
+    // as an invalid snapshot file.
+    // In either case an exit code of 253 is considered a crash.
     if (exitCode == 253) return true;
     if (io.Platform.operatingSystem == 'windows') {
       // The VM uses std::abort to terminate on asserts.
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index b29c3f0..b7aaedb 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1551,17 +1551,8 @@
     List<String> dartOptions = optionsFromFile["dartOptions"];
 
     assert(!isMultitest || dartOptions == null);
-    if (dartOptions == null) {
-      args.add(filePath.toNativePath());
-    } else {
-      var executable_name = dartOptions[0];
-      // TODO(ager): Get rid of this hack when the runtime checkout goes away.
-      var file = new File(executable_name);
-      if (!file.existsSync()) {
-        executable_name = '../$executable_name';
-        assert(new File(executable_name).existsSync());
-        dartOptions[0] = executable_name;
-      }
+    args.add(filePath.toNativePath());
+    if (dartOptions != null) {
       args.addAll(dartOptions);
     }