Version 1.9.0-dev.8.3

svn merge -c 43714 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43772 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43809 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43821 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43824 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43827 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43836 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43839 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43719,43754,43812,43813,43758 https://dart.googlecode.com/svn/branches/bleeding_edge trunk (conflicts resolved by https://codereview.chromium.org/929053005)

git-svn-id: http://dart.googlecode.com/svn/trunk@43844 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 f5430ac..0e50099 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -334,21 +334,6 @@
   }
 
   /**
-   * Performs all scheduled analysis operations.
-   */
-  void test_performAllAnalysisOperations() {
-    while (true) {
-      ServerOperation operation = operationQueue.takeIf((operation) {
-        return operation is PerformAnalysisOperation;
-      });
-      if (operation == null) {
-        break;
-      }
-      operation.perform(this);
-    }
-  }
-
-  /**
    * If the given notice applies to a file contained within an analysis root,
    * notify interested parties that the file has been (at least partially)
    * analyzed.
@@ -474,23 +459,6 @@
     return context.getErrors(source);
   }
 
-// TODO(brianwilkerson) Add the following method after 'prioritySources' has
-// been added to InternalAnalysisContext.
-//  /**
-//   * Return a list containing the full names of all of the sources that are
-//   * priority sources.
-//   */
-//  List<String> getPriorityFiles() {
-//    List<String> priorityFiles = new List<String>();
-//    folderMap.values.forEach((ContextDirectory directory) {
-//      InternalAnalysisContext context = directory.context;
-//      context.prioritySources.forEach((Source source) {
-//        priorityFiles.add(source.fullName);
-//      });
-//    });
-//    return priorityFiles;
-//  }
-
   /**
    * Returns resolved [AstNode]s at the given [offset] of the given [file].
    *
@@ -508,6 +476,23 @@
     return nodes;
   }
 
+// TODO(brianwilkerson) Add the following method after 'prioritySources' has
+// been added to InternalAnalysisContext.
+//  /**
+//   * Return a list containing the full names of all of the sources that are
+//   * priority sources.
+//   */
+//  List<String> getPriorityFiles() {
+//    List<String> priorityFiles = new List<String>();
+//    folderMap.values.forEach((ContextDirectory directory) {
+//      InternalAnalysisContext context = directory.context;
+//      context.prioritySources.forEach((Source source) {
+//        priorityFiles.add(source.fullName);
+//      });
+//    });
+//    return priorityFiles;
+//  }
+
   /**
    * Returns resolved [CompilationUnit]s of the Dart file with the given [path].
    *
@@ -965,6 +950,21 @@
   }
 
   /**
+   * Performs all scheduled analysis operations.
+   */
+  void test_performAllAnalysisOperations() {
+    while (true) {
+      ServerOperation operation = operationQueue.takeIf((operation) {
+        return operation is PerformAnalysisOperation;
+      });
+      if (operation == null) {
+        break;
+      }
+      operation.perform(this);
+    }
+  }
+
+  /**
    * Implementation for `analysis.updateContent`.
    */
   void updateContent(String id, Map<String, dynamic> changes) {
@@ -1165,7 +1165,7 @@
       _onContextsChangedController.stream;
 
   @override
-  void addContext(Folder folder, UriResolver packageUriResolver) {
+  AnalysisContext addContext(Folder folder, UriResolver packageUriResolver) {
     InternalAnalysisContext context =
         AnalysisEngine.instance.createAnalysisContext();
     context.contentCache = analysisServer._overlayState;
@@ -1175,6 +1175,7 @@
     _onContextsChangedController.add(
         new ContextsChangedEvent(added: [context]));
     analysisServer.schedulePerformAnalysisOperation(context);
+    return context;
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index fc42e65..999c975 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -36,6 +36,11 @@
  */
 abstract class ContextManager {
   /**
+   * The name of the `lib` directory.
+   */
+  static const String LIB_DIR_NAME = 'lib';
+
+  /**
    * [_ContextInfo] object for each included directory in the most
    * recent successful call to [setRoots].
    */
@@ -85,9 +90,9 @@
   }
 
   /**
-   * Called when a new context needs to be created.
+   * Create and return a new analysis context.
    */
-  void addContext(Folder folder, UriResolver packageUriResolver);
+  AnalysisContext addContext(Folder folder, UriResolver packageUriResolver);
 
   /**
    * Called when the set of files associated with a context have changed (or
@@ -282,7 +287,8 @@
   /**
    * Resursively adds all Dart and HTML files to the [changeSet].
    */
-  void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) {
+  void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info,
+      bool pubspecExists, bool createPackageUri) {
     if (info.excludesResource(folder) || folder.shortName.startsWith('.')) {
       return;
     }
@@ -297,14 +303,47 @@
       if (child is File) {
         if (_shouldFileBeAnalyzed(child)) {
           Source source = child.createSource();
+          if (createPackageUri) {
+            //
+            // It should be possible to generate the uri by executing:
+            //
+            //   Uri uri = info.context.sourceFactory.restoreUri(source);
+            //
+            // but for some reason this doesn't produce the same result as the
+            // code below. This needs to be investigated.
+            // (See https://code.google.com/p/dart/issues/detail?id=22463).
+            //
+            String packagePath = info.folder.path;
+            String packageName =
+                resourceProvider.pathContext.basename(packagePath);
+            String libPath =
+                resourceProvider.pathContext.join(packagePath, LIB_DIR_NAME);
+            String relPath = source.fullName.substring(libPath.length);
+            Uri uri =
+                Uri.parse('${PackageMapUriResolver.PACKAGE_SCHEME}:$packageName$relPath');
+            source = child.createSource(uri);
+          }
           changeSet.addedSource(source);
           info.sources[path] = source;
         }
       } else if (child is Folder) {
-        if (child.shortName == PACKAGES_NAME) {
+        String shortName = child.shortName;
+        if (shortName == PACKAGES_NAME) {
           continue;
         }
-        _addSourceFiles(changeSet, child, info);
+        if (pubspecExists &&
+            !createPackageUri &&
+            shortName == LIB_DIR_NAME &&
+            child.parent == info.folder) {
+          _addSourceFiles(changeSet, child, info, pubspecExists, true);
+        } else {
+          _addSourceFiles(
+              changeSet,
+              child,
+              info,
+              pubspecExists,
+              createPackageUri);
+        }
       }
     }
   }
@@ -338,15 +377,19 @@
   /**
    * Create a new empty context associated with [folder].
    */
-  _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) {
-    _ContextInfo info =
-        new _ContextInfo(folder, children, normalizedPackageRoots[folder.path]);
+  _ContextInfo _createContext(Folder folder, File pubspecFile,
+      List<_ContextInfo> children) {
+    _ContextInfo info = new _ContextInfo(
+        folder,
+        pubspecFile,
+        children,
+        normalizedPackageRoots[folder.path]);
     _contexts[folder] = info;
     info.changeSubscription = folder.changes.listen((WatchEvent event) {
       _handleWatchEvent(folder, info, event);
     });
     UriResolver packageUriResolver = _computePackageUriResolver(folder, info);
-    addContext(folder, packageUriResolver);
+    info.context = addContext(folder, packageUriResolver);
     return info;
   }
 
@@ -365,13 +408,16 @@
    * Returns create pubspec-based contexts.
    */
   List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) {
-    // check if there is a pubspec in the folder
-    {
-      File pubspecFile = folder.getChild(PUBSPEC_NAME);
-      if (pubspecFile.exists) {
-        _ContextInfo info = _createContextWithSources(folder, <_ContextInfo>[]);
-        return [info];
-      }
+    // check whether there is a pubspec in the folder
+    File pubspecFile = folder.getChild(PUBSPEC_NAME);
+    bool pubspecExists = pubspecFile.exists;
+    if (pubspecExists) {
+      _ContextInfo info = _createContextWithSources(
+          folder,
+          pubspecFile,
+          pubspecExists,
+          <_ContextInfo>[]);
+      return [info];
     }
     // try to find subfolders with pubspec files
     List<_ContextInfo> children = <_ContextInfo>[];
@@ -386,18 +432,21 @@
       return children;
     }
     // OK, create a context without a pubspec
-    _createContextWithSources(folder, children);
+    _createContextWithSources(folder, pubspecFile, pubspecExists, children);
     return children;
   }
 
   /**
-   * Create a new context associated with [folder] and fills its with sources.
+   * Create a new context associated with the given [folder]. The [pubspecFile]
+   * is the `pubspec.yaml` file contained in the folder, and [pubspecExists] is
+   * `true` if the file exists. Add any sources that are not included in one of
+   * the [children] to the context.
    */
-  _ContextInfo _createContextWithSources(Folder folder,
-      List<_ContextInfo> children) {
-    _ContextInfo info = _createContext(folder, children);
+  _ContextInfo _createContextWithSources(Folder folder, File pubspecFile,
+      bool pubspecExists, List<_ContextInfo> children) {
+    _ContextInfo info = _createContext(folder, pubspecFile, children);
     ChangeSet changeSet = new ChangeSet();
-    _addSourceFiles(changeSet, folder, info);
+    _addSourceFiles(changeSet, folder, info, pubspecExists, false);
     applyChangesToContext(folder, changeSet);
     return info;
   }
@@ -416,7 +465,7 @@
    */
   void _extractContext(_ContextInfo oldInfo, File pubspecFile) {
     Folder newFolder = pubspecFile.parent;
-    _ContextInfo newInfo = _createContext(newFolder, []);
+    _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []);
     newInfo.parent = oldInfo;
     // prepare sources to extract
     Map<String, Source> extractedSources = new HashMap<String, Source>();
@@ -629,6 +678,11 @@
   StreamSubscription<WatchEvent> changeSubscription;
 
   /**
+   * The analysis context that was created for the [folder].
+   */
+  AnalysisContext context;
+
+  /**
    * Map from full path to the [Source] object, for each source that has been
    * added to the context.
    */
@@ -640,8 +694,8 @@
    */
   Set<String> packageMapDependencies;
 
-  _ContextInfo(this.folder, this.children, this.packageRoot) {
-    pubspecPath = folder.getChild(PUBSPEC_NAME).path;
+  _ContextInfo(this.folder, File pubspecFile, this.children, this.packageRoot) {
+    pubspecPath = pubspecFile.path;
     for (_ContextInfo child in children) {
       child.parent = this;
     }
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 6cde096..fd4d116 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -4,6 +4,8 @@
 
 library test.context.directory.manager;
 
+import 'dart:collection';
+
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
@@ -27,12 +29,44 @@
 
 @reflectiveTest
 class ContextManagerTest {
+  /**
+   * The name of the 'bin' directory.
+   */
+  static const String BIN_NAME = 'bin';
+  /**
+   * The name of the 'lib' directory.
+   */
+  static const String LIB_NAME = 'lib';
+  /**
+   * The name of the 'src' directory.
+   */
+  static const String SRC_NAME = 'src';
+
+  /**
+   * The name of the 'test' directory.
+   */
+  static const String TEST_NAME = 'test';
+
   TestContextManager manager;
+
   MemoryResourceProvider resourceProvider;
+
   MockPackageMapProvider packageMapProvider;
 
   String projPath = '/my/proj';
 
+  String newFile(List<String> pathComponents, [String content = '']) {
+    String filePath = posix.joinAll(pathComponents);
+    resourceProvider.newFile(filePath, content);
+    return filePath;
+  }
+
+  String newFolder(List<String> pathComponents) {
+    String folderPath = posix.joinAll(pathComponents);
+    resourceProvider.newFolder(folderPath);
+    return folderPath;
+  }
+
   void setUp() {
     resourceProvider = new MemoryResourceProvider();
     packageMapProvider = new MockPackageMapProvider();
@@ -174,6 +208,32 @@
     expect(manager.currentContextFilePaths[projPath], hasLength(0));
   }
 
+  void test_setRoots_addFolderWithPubspecAndLib() {
+    String binPath = newFolder([projPath, BIN_NAME]);
+    String libPath = newFolder([projPath, LIB_NAME]);
+    String srcPath = newFolder([libPath, SRC_NAME]);
+    String testPath = newFolder([projPath, TEST_NAME]);
+
+    newFile([projPath, PUBSPEC_NAME]);
+    String appPath = newFile([binPath, 'app.dart']);
+    newFile([libPath, 'main.dart']);
+    newFile([srcPath, 'internal.dart']);
+    String testFilePath = newFile([testPath, 'main_test.dart']);
+
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    Set<Source> sources = manager.currentContextSources[projPath];
+
+    expect(manager.currentContextPaths, hasLength(1));
+    expect(manager.currentContextPaths, contains(projPath));
+    expect(sources, hasLength(4));
+    List<String> uris =
+        sources.map((Source source) => source.uri.toString()).toList();
+    expect(uris, contains('file://$appPath'));
+    expect(uris, contains('package:proj/main.dart'));
+    expect(uris, contains('package:proj/src/internal.dart'));
+    expect(uris, contains('file://$testFilePath'));
+  }
+
   void test_setRoots_addFolderWithPubspecFolders() {
     // prepare paths
     String root = '/root';
@@ -792,6 +852,13 @@
       Map<String, int>>{};
 
   /**
+   * A map from the paths of contexts to a set of the sources that should be
+   * explicitly analyzed in those contexts.
+   */
+  final Map<String, Set<Source>> currentContextSources = <String,
+      Set<Source>>{};
+
+  /**
    * Map from context to package URI resolver.
    */
   final Map<String, UriResolver> currentContextPackageUriResolvers = <String,
@@ -807,24 +874,30 @@
   Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
 
   @override
-  void addContext(Folder folder, UriResolver packageUriResolver) {
+  AnalysisContext addContext(Folder folder, UriResolver packageUriResolver) {
     String path = folder.path;
     expect(currentContextPaths, isNot(contains(path)));
     currentContextTimestamps[path] = now;
     currentContextFilePaths[path] = <String, int>{};
+    currentContextSources[path] = new HashSet<Source>();
     currentContextPackageUriResolvers[path] = packageUriResolver;
+    return null;
   }
 
   @override
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
     Map<String, int> filePaths = currentContextFilePaths[contextFolder.path];
+    Set<Source> sources = currentContextSources[contextFolder.path];
+
     for (Source source in changeSet.addedSources) {
       expect(filePaths, isNot(contains(source.fullName)));
       filePaths[source.fullName] = now;
+      sources.add(source);
     }
     for (Source source in changeSet.removedSources) {
       expect(filePaths, contains(source.fullName));
       filePaths.remove(source.fullName);
+      sources.remove(source);
     }
     for (Source source in changeSet.changedSources) {
       expect(filePaths, contains(source.fullName));
@@ -847,6 +920,7 @@
     expect(currentContextPaths, contains(path));
     currentContextTimestamps.remove(path);
     currentContextFilePaths.remove(path);
+    currentContextSources.remove(path);
     currentContextPackageUriResolvers.remove(path);
   }
 
diff --git a/pkg/analyzer/lib/source/package_map_resolver.dart b/pkg/analyzer/lib/source/package_map_resolver.dart
index badaf3a..37de62a 100644
--- a/pkg/analyzer/lib/source/package_map_resolver.dart
+++ b/pkg/analyzer/lib/source/package_map_resolver.dart
@@ -83,7 +83,7 @@
         String pkgFolderPath = pkgFolder.path;
         if (sourcePath.startsWith(pkgFolderPath)) {
           String relPath = sourcePath.substring(pkgFolderPath.length);
-          return new Uri(path: '$PACKAGE_SCHEME:$pkgName$relPath');
+          return Uri.parse('$PACKAGE_SCHEME:$pkgName$relPath');
         }
       }
     }
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index c76cef7..9898b75 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -10343,7 +10343,7 @@
     }
     if (scriptAttribute != null) {
       try {
-        Uri uri = new Uri(path: scriptAttribute.text);
+        Uri uri = Uri.parse(scriptAttribute.text);
         String fileName = uri.path;
         Source librarySource =
             _task.context.sourceFactory.resolveUri(_task.source, fileName);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index a40c7e6..f130d40 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -7913,36 +7913,18 @@
    */
   LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) {
     //
-    // Create the objects representing the library being resolved and the core
-    // library.
+    // Create the object representing the library being resolved and compute
+    // the dependency relationship.  Note that all libraries depend implicitly
+    // on core, and we inject an ersatz dependency on async, so once this is
+    // done the core and async library elements will have been created.
     //
     Library targetLibrary = createLibrary(librarySource);
+    _computeLibraryDependencies(targetLibrary);
     _coreLibrary = _libraryMap[_coreLibrarySource];
-    if (_coreLibrary == null) {
-      // This should only happen if the library being analyzed is the core
-      // library.
-      _coreLibrary = _createLibraryOrNull(_coreLibrarySource);
-      if (_coreLibrary == null) {
-        LibraryResolver2.missingCoreLibrary(
-            analysisContext,
-            _coreLibrarySource);
-      }
-    }
     _asyncLibrary = _libraryMap[_asyncLibrarySource];
-    if (_asyncLibrary == null) {
-      // This should only happen if the library being analyzed is the async
-      // library.
-      _asyncLibrary = _createLibraryOrNull(_asyncLibrarySource);
-      if (_asyncLibrary == null) {
-        LibraryResolver2.missingAsyncLibrary(
-            analysisContext,
-            _asyncLibrarySource);
-      }
-    }
     //
     // Compute the set of libraries that need to be resolved together.
     //
-    _computeLibraryDependencies(targetLibrary);
     _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
     //
     // Build the element models representing the libraries being resolved.
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 18af984..c1c294b 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -38,6 +38,10 @@
 import 'parser_test.dart';
 import 'resolver_test.dart';
 import 'test_support.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:path/src/context.dart';
 
 
 main() {
@@ -8474,6 +8478,32 @@
         result.fullName,
         FileUtilities2.createFile("/does/not/exist.dart").getAbsolutePath());
   }
+
+  void test_resolveUri_nonAbsolute_relative_package() {
+    MemoryResourceProvider provider = new MemoryResourceProvider();
+    Context context = provider.pathContext;
+    String packagePath = context.joinAll([context.separator, 'path', 'to', 'package']);
+    String libPath = context.joinAll([packagePath, 'lib']);
+    String dirPath = context.joinAll([libPath, 'dir']);
+    String firstPath = context.joinAll([dirPath, 'first.dart']);
+    String secondPath = context.joinAll([dirPath, 'second.dart']);
+
+    provider.newFolder(packagePath);
+    Folder libFolder =  provider.newFolder(libPath);
+    provider.newFolder(dirPath);
+    File firstFile = provider.newFile(firstPath, '');
+    provider.newFile(secondPath, '');
+
+    PackageMapUriResolver resolver = new PackageMapUriResolver(provider, {'package' : [libFolder]});
+    SourceFactory factory = new SourceFactory([resolver]);
+    Source librarySource = firstFile.createSource(Uri.parse('package:package/dir/first.dart'));
+
+    Source result = factory.resolveUri(librarySource, 'second.dart');
+    expect(result, isNotNull);
+    expect(result.fullName, secondPath);
+    expect(result.uri.toString(), 'package:package/dir/second.dart');
+  }
+
   void test_restoreUri() {
     JavaFile file1 = FileUtilities2.createFile("/some/file1.dart");
     JavaFile file2 = FileUtilities2.createFile("/some/file2.dart");
diff --git a/pkg/analyzer/test/source/package_map_resolver_test.dart b/pkg/analyzer/test/source/package_map_resolver_test.dart
index a12e361..0869c56 100644
--- a/pkg/analyzer/test/source/package_map_resolver_test.dart
+++ b/pkg/analyzer/test/source/package_map_resolver_test.dart
@@ -162,13 +162,13 @@
       Source source = _createFileSource('/pkgA/lib/libA.dart');
       Uri uri = resolver.restoreAbsolute(source);
       expect(uri, isNotNull);
-      expect(uri.path, 'package:pkgA/libA.dart');
+      expect(uri.toString(), 'package:pkgA/libA.dart');
     }
     {
       Source source = _createFileSource('/pkgB/lib/src/libB.dart');
       Uri uri = resolver.restoreAbsolute(source);
       expect(uri, isNotNull);
-      expect(uri.path, 'package:pkgB/src/libB.dart');
+      expect(uri.toString(), 'package:pkgB/src/libB.dart');
     }
     {
       Source source = _createFileSource('/no/such/file');
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 713cbc1..fd27d88 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -475,7 +475,7 @@
    * Returns the type as an instance of class [other], if possible, null
    * otherwise.
    */
-  DartType asInstanceOf(ClassElement other) {
+  InterfaceType asInstanceOf(ClassElement other) {
     other = other.declaration;
     if (element == other) return this;
     InterfaceType supertype = element.asInstanceOf(other);
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 656b1af..961ec7b 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -4,13 +4,17 @@
 
 library rewrite_async;
 
-// TODO(sigurdm): Throws in catch-handlers are handled wrong.
 // TODO(sigurdm): Avoid using variables in templates. It could blow up memory
 // use.
+// TODO(sigurdm): Move the try/catch expression to a js_helper function.
+// That would also simplify the sync* case, where the error can just be thrown.
 
 import "dart:math" show max;
 import 'dart:collection';
 
+import 'package:_internal/compiler/js_lib/shared/async_await_error_codes.dart'
+    as error_codes;
+
 import "js.dart" as js;
 
 import '../util/util.dart';
@@ -37,14 +41,39 @@
 
   Map<js.Node, int> continueLabels = new Map<js.Node, int>();
   Map<js.Node, int> breakLabels = new Map<js.Node, int>();
-  Map<js.Node, int> finallyLabels = new Map<js.Node, int>();
-  int exitLabel;
 
-  // A stack of all enclosing jump targets (including the function for
-  // representing the target of a return, and all enclosing try-blocks that have
-  // finally part, this way ensuring all the finally blocks between a jump and
-  // its target are run before the jump.
-  List<js.Node> targetsAndTries = new List<js.Node>();
+  /// The label of a finally part.
+  Map<js.Block, int> finallyLabels = new Map<js.Block, int>();
+
+  /// The label of the catch handler of a [js.Try] or a [js.Fun] or [js.Catch].
+  ///
+  /// These mark the points an error can be consumed.
+  ///
+  /// - The handler of a [js.Fun] is the outermost and will rethrow the error.
+  /// - The handler of a [js.Try] will run the catch handler.
+  /// - The handler of a [js.Catch] is a synthetic handler that ensures the
+  ///   right finally blocks are run if an error is thrown inside a
+  ///   catch-handler.
+  Map<js.Node, int> handlerLabels = new Map<js.Node, int>();
+
+  int exitLabel;
+  int rethrowLabel;
+
+  /// A stack of all (surrounding) jump targets.
+  ///
+  /// Jump targets are:
+  ///
+  /// * The function, signalling a return or uncaught throw.
+  /// * Loops.
+  /// * LabeledStatements (also used for 'continue' when attached to loops).
+  /// * Try statements, for catch and finally handlers.
+  /// * Catch handlers, when inside a catch-part of a try, the catch-handler is
+  ///   used to associate with a synthetic handler that will ensure the right
+  ///   finally blocks are visited.
+  ///
+  /// When jumping to a target it is necessary to visit all finallies that
+  /// are on the way to target (i.e. more nested than the jump target).
+  List<js.Node> jumpTargets = new List<js.Node>();
 
   List<int> continueStack = new List<int>();
   List<int> breakStack = new List<int>();
@@ -55,8 +84,6 @@
 
   PreTranslationAnalysis analysis;
 
-  List<int> errorHandlerLabels = new List<int>();
-
   final Function safeVariableName;
 
   // All the <x>Name variables are names of Javascript variables used in the
@@ -86,13 +113,17 @@
   ///   }
   /// }
   ///
-  /// It is a parameter to the [helperName] function, so that [thenHelper] and
-  /// [streamHelper] can call [helperName] with the result of an awaited Future.
+  /// It is a parameter to the [bodyName] function, so that [asyncHelper] and
+  /// [streamHelper] can call [bodyName] with the result of an awaited Future.
   String resultName;
 
+  /// A parameter to the [bodyName] function. Indicating if we are in success
+  /// or error case.
+  String errorCodeName;
+
   /// The name of the inner function that is scheduled to do each await/yield,
   /// and called to do a new iteration for sync*.
-  String helperName;
+  String bodyName;
 
   /// The Completer that will finish an async function.
   ///
@@ -121,9 +152,16 @@
   /// the last.
   String nextName;
 
+  /// The stack of labels of finally blocks to assign to [nextName] if the
+  /// async* [StreamSubscription] was canceled during a yield.
+  String nextWhenCanceledName;
+
   /// The current returned value (a finally block may overwrite it).
   String returnValueName;
 
+  /// If we are in the process of handling an error, stores the current error.
+  String currentErrorName;
+
   /// The label of the outer loop.
   ///
   /// Used if there are untransformed loops containing break or continues to
@@ -131,7 +169,7 @@
   String outerLabelName;
 
   /// If javascript `this` is used, it is accessed via this variable, in the
-  /// [helperName] function.
+  /// [bodyName] function.
   String selfName;
 
   // These expressions are hooks for communicating with the runtime.
@@ -141,19 +179,21 @@
   /// For an await it is called with:
   ///
   /// - The value to await
-  /// - The [helperName]
-  /// - The [completerName]
-  /// - A JavaScript function that is executed if the future completed with
-  ///   an error. That function is responsible for executing the right error
-  ///   handler and/or finally blocks).
+  /// - The body function [bodyName]
+  /// - The completer object [completerName]
   ///
   /// For a return it is called with:
   ///
   /// - The value to complete the completer with.
-  /// - null
-  /// - The [completerName]
-  /// - null.
-  final js.Expression thenHelper;
+  /// - [error_codes.SUCCESS]
+  /// - The completer object [completerName]
+  ///
+  /// For a throw it is called with:
+  ///
+  /// - The error to complete the completer with.
+  /// - [error_codes.ERROR]
+  /// - The completer object [completerName]
+  final js.Expression asyncHelper;
 
   /// The function called by an async* function to simulate an await, yield or
   /// yield*.
@@ -162,11 +202,8 @@
   ///
   /// - The value to await/yieldExpression(value to yield)/
   /// yieldStarExpression(stream to yield)
-  /// - The [helperName]
-  /// - The [controllerName]
-  /// - A JavaScript function that is executed if the future completed with
-  ///   an error. That function is responsible for executing the right error
-  ///   handler and/or finally blocks).
+  /// - The body function [bodyName]
+  /// - The controller object [controllerName]
   ///
   /// For a return it is called with:
   ///
@@ -192,7 +229,7 @@
   final js.Expression streamOfController;
 
   /// Contructor creating the Iterable for a sync* method. Called with
-  /// [helperName].
+  /// [bodyName].
   final js.Expression newIterable;
 
   /// A JS Expression that creates a marker showing that iteration is over.
@@ -210,6 +247,9 @@
   /// Called with the stream to yield from.
   final js.Expression yieldStarExpression;
 
+  /// Used by sync* functions to throw exeptions.
+  final js.Expression uncaughtErrorExpression;
+
   final DiagnosticListener diagnosticListener;
   // For error reporting only.
   Spannable get spannable {
@@ -235,7 +275,7 @@
 
   AsyncRewriter(this.diagnosticListener,
                 spannable,
-                {this.thenHelper,
+                {this.asyncHelper,
                  this.streamHelper,
                  this.streamOfController,
                  this.newCompleter,
@@ -244,6 +284,7 @@
                  this.newIterable,
                  this.yieldExpression,
                  this.yieldStarExpression,
+                 this.uncaughtErrorExpression,
                  this.safeVariableName})
       : _spannable = spannable;
 
@@ -263,14 +304,17 @@
     // To avoid name collisions with existing names, the fresh names are
     // generated after the analysis.
     resultName = freshName("result");
+    errorCodeName = freshName("errorCode");
     completerName = freshName("completer");
     controllerName = freshName("controller");
-    helperName = freshName("helper");
+    bodyName = freshName("body");
     gotoName = freshName("goto");
     handlerName = freshName("handler");
     errorName = freshName("error");
     nextName = freshName("next");
+    nextWhenCanceledName = freshName("nextWhenCanceled");
     returnValueName = freshName("returnValue");
+    currentErrorName = freshName("currentError");
     outerLabelName = freshName("outer");
     selfName = freshName("self");
 
@@ -278,9 +322,8 @@
   }
 
   js.Expression get currentErrorHandler {
-    return errorHandlerLabels.isEmpty
-        ? new js.LiteralNull()
-        : js.number(errorHandlerLabels.last);
+    return js.number(handlerLabels[jumpTargets.lastWhere(
+        (node) => handlerLabels[node] != null)]);
   }
 
   int allocateTempVar() {
@@ -542,7 +585,7 @@
   /// through all the enclosing finally blocks). The jump to here is made in
   /// [visitReturn].
   ///
-  /// Returning from an async method calls the [thenHelper] with the result.
+  /// Returning from an async method calls the [asyncHelper] with the result.
   /// (the result might have been stored in [returnValueName] by some finally
   /// block).
   ///
@@ -561,26 +604,40 @@
         String returnValue =
             analysis.hasExplicitReturns ? returnValueName : "null";
         addStatement(js.js.statement(
-            "return #thenHelper($returnValue, null, $completerName, null)", {
-          "thenHelper": thenHelper
-        }));
+            "return #thenHelper($returnValue, #successCode, "
+                "$completerName, null)", {
+             "thenHelper": asyncHelper,
+             "successCode": js.number(error_codes.SUCCESS)}));
         break;
       case const js.AsyncModifier.syncStar():
         addStatement(new js.Return(new js.Call(endOfIteration, [])));
         break;
       case const js.AsyncModifier.asyncStar():
         addStatement(js.js.statement(
-            "return #streamHelper(null, null, $controllerName, null)", {
-          "streamHelper": streamHelper
-        }));
+            "return #streamHelper(null, #successCode, $controllerName)", {
+          "streamHelper": streamHelper,
+          "successCode": js.number(error_codes.SUCCESS)}));
         break;
       default:
         diagnosticListener.internalError(
             spannable, "Internal error, unexpected asyncmodifier $async");
     }
+    if (isAsync || isAsyncStar) {
+      beginLabel(rethrowLabel);
+      addStatement(js.js.statement(
+          "return #thenHelper($currentErrorName, #errorCode, "
+          "${isAsync ? completerName : controllerName})", {
+            "thenHelper": isAsync ? asyncHelper : streamHelper,
+            "errorCode": js.number(error_codes.ERROR)}));
+    } else {
+      assert(isSyncStar);
+      beginLabel(rethrowLabel);
+      addStatement(new js.Return(new js.Call(uncaughtErrorExpression,
+          [new js.VariableUse(currentErrorName)])));
+    }
   }
 
-  /// The initial call to [thenHelper]/[streamHelper].
+  /// The initial call to [asyncHelper]/[streamHelper].
   ///
   /// There is no value to await/yield, so the first argument is `null` and
   /// also the errorCallback is `null`.
@@ -590,8 +647,8 @@
   js.Statement generateInitializer() {
     if (isAsync) {
       return js.js.statement(
-          "return #thenHelper(null, $helperName, $completerName, null);", {
-        "thenHelper": thenHelper
+          "return #asyncHelper(null, $bodyName, $completerName, null);", {
+        "asyncHelper": asyncHelper
       });
     } else if (isAsyncStar) {
       return js.js.statement(
@@ -607,17 +664,17 @@
   /// Rewrites an async/sync*/async* function to a normal Javascript function.
   ///
   /// The control flow is flattened by simulating 'goto' using a switch in a
-  /// loop and a state variable [gotoName] inside a helper-function that can be
-  /// called back by [thenHelper]/[streamHelper]/the [Iterator].
+  /// loop and a state variable [gotoName] inside a nested function [bodyName]
+  /// that can be called back by [asyncHelper]/[asyncStarHelper]/the [Iterator].
   ///
   /// Local variables are hoisted outside the helper.
   ///
   /// Awaits in async/async* are translated to code that remembers the current
   /// location (so the function can resume from where it was) followed by a call
-  /// to the [thenHelper]. The helper sets up the waiting for the awaited value
+  /// to the [asyncHelper]. The helper sets up the waiting for the awaited value
   /// and returns a future which is immediately returned by the translated
   /// await.
-  /// Yields in async* are translated to a call to the [streamHelper]. They,
+  /// Yields in async* are translated to a call to the [asyncStarHelper]. They,
   /// too, need to be prepared to be interrupted in case the stream is paused or
   /// canceled. (Currently we always suspend - this is different from the spec,
   /// see `streamHelper` in `js_helper.dart`).
@@ -635,7 +692,7 @@
   ///   return bar(p);
   /// }
   ///
-  /// Becomes:
+  /// Becomes (without error handling):
   ///
   /// function(x, y, z) {
   ///   var goto = 0, returnValue, completer = new Completer(), p;
@@ -644,17 +701,17 @@
   ///       switch (goto) {
   ///         case 0:
   ///           goto = 1 // Remember where to continue when the future succeeds.
-  ///           return thenHelper(foo(), helper, completer, null);
+  ///           return thenHelper(foo(), helper, completer);
   ///         case 1:
   ///           p = result;
   ///           returnValue = bar(p);
   ///           goto = 2;
   ///           break;
   ///         case 2:
-  ///           return thenHelper(returnValue, null, completer, null)
+  ///           return thenHelper(returnValue, null, completer)
   ///       }
   ///     }
-  ///     return thenHelper(null, helper, completer, null);
+  ///     return thenHelper(null, helper, completer);
   ///   }
   /// }
   ///
@@ -689,11 +746,16 @@
   ///   var goto = 0;
   ///   var returnValue;
   ///   var completer = new Completer();
-  ///   var handler = null;
+  ///   var handler = 8; // Outside try-blocks go to the rethrow label.
   ///   var p;
+  ///   var storedError;
   ///   // The result can be either the result of an awaited future, or an
   ///   // error if the future completed with an error.
-  ///   function helper(result) {
+  ///   function helper(errorCode, result) {
+  ///     if (errorCode == 1) {
+  ///       storedError = result;
+  ///       goto = handler;
+  ///     }
   ///     while (true) {
   ///       try {
   ///         switch (goto) {
@@ -718,7 +780,9 @@
   ///             goto = 5; // finally handler for outer try.
   ///             break;
   ///           case 4: // catch handler for outer try.
-  ///             e = result;
+  ///             handler = 5; // If the handler throws, do the finally ..
+  ///             next = [8] // ... and rethrow.
+  ///             e = storedError;
   ///             handle(e);
   ///             // Fall through to finally.
   ///           case 5: // finally handler for outer try.
@@ -728,14 +792,16 @@
   ///             break;
   ///           case 6: // Exiting outer try.
   ///           case 7: // return
-  ///             return thenHelper(returnValue, null, completer, null);
+  ///             return thenHelper(returnValue, 0, completer);
+  ///           case 8: // Rethrow
+  ///             return thenHelper(storedError, 1, completer);
   ///         }
   ///       } catch (error) {
-  ///         result = error;
+  ///         storedError = error;
   ///         goto = handler;
   ///       }
   ///     }
-  ///     return thenHelper(null, helper, completer, null);
+  ///     return thenHelper(null, helper, completer);
   ///   }
   /// }
   ///
@@ -748,10 +814,12 @@
     // [visitDartYield].
     exitLabel =
         analysis.hasExplicitReturns || isAsyncStar ? newLabel("return") : null;
+    rethrowLabel = newLabel("rethrow");
+    handlerLabels[node] = rethrowLabel;
     js.Statement body = node.body;
-    targetsAndTries.add(node);
+    jumpTargets.add(node);
     visitStatement(body);
-    targetsAndTries.removeLast();
+    jumpTargets.removeLast();
     addExit();
 
     List<js.SwitchClause> clauses = labelledParts.keys.map((label) {
@@ -762,17 +830,13 @@
     if (hasJumpThoughOuterLabel) {
       helperBody = js.js.statement("$outerLabelName: #", [helperBody]);
     }
-    if (hasTryBlocks) {
-      helperBody = js.js.statement("""
-          try {
-            #body
-          } catch ($errorName){
-            if ($handlerName === null)
-              throw $errorName;
-            $resultName = $errorName;
-            $gotoName = $handlerName;
-          }""", {"body": helperBody});
-    }
+    helperBody = js.js.statement("""
+        try {
+          #body
+        } catch ($errorName){
+          $currentErrorName = $errorName;
+          $gotoName = $handlerName;
+        }""", {"body": helperBody});
     List<js.VariableInitialization> inits = <js.VariableInitialization>[];
 
     js.VariableInitialization makeInit(String name, js.Expression initValue) {
@@ -785,17 +849,19 @@
       inits.add(makeInit(completerName, new js.New(newCompleter, [])));
     } else if (isAsyncStar) {
       inits.add(makeInit(controllerName,
-          new js.Call(newController, [new js.VariableUse(helperName)])));
+          new js.Call(newController, [new js.VariableUse(bodyName)])));
     }
-    if (hasTryBlocks) {
-      inits.add(makeInit(handlerName, new js.LiteralNull()));
-    }
-    if (hasJumpThroughFinally) {
+    inits.add(makeInit(handlerName, js.number(rethrowLabel)));
+    inits.add(makeInit(currentErrorName, null));
+    if (hasJumpThroughFinally || analysis.hasYield) {
       inits.add(makeInit(nextName, null));
     }
     if (analysis.hasExplicitReturns && isAsync) {
       inits.add(makeInit(returnValueName, null));
     }
+    if (isSyncStar) {
+      inits.add(makeInit(resultName, null));
+    }
     if (analysis.hasThis && !isSyncStar) {
       // Sync* functions must remember `this` on the level of the outer
       // function.
@@ -807,6 +873,7 @@
     inits.addAll(new Iterable.generate(tempVarHighWaterMark,
         (int i) => makeInit(useTempVar(i + 1).name, null)));
     js.VariableDeclarationList varDecl = new js.VariableDeclarationList(inits);
+    // TODO(sigurdm): Explain the difference between these cases.
     if (isSyncStar) {
       return js.js("""
           function (#params) {
@@ -814,7 +881,7 @@
               var $selfName = this;
             return new #newIterable(function () {
               #varDecl;
-              return function $helperName($resultName) {
+              return function $bodyName() {
                 while (true)
                   #helperBody;
               };
@@ -831,15 +898,33 @@
     return js.js("""
         function (#params) {
           #varDecl;
-          function $helperName($resultName) {
+          function $bodyName($errorCodeName, $resultName) {
+            if (#hasYield)
+              switch ($errorCodeName) {
+                case #streamWasCanceled:
+                  $nextName = $nextWhenCanceledName;
+                  $gotoName = $nextName.pop();
+                  break;
+                case #errorCode:
+                  $currentErrorName = $resultName;
+                  $gotoName = $handlerName;
+              }
+            else
+              if ($errorCodeName == #errorCode) {
+                  $currentErrorName = $resultName;
+                  $gotoName = $handlerName;
+              }
             while (true)
               #helperBody;
           }
           #init;
         }""", {
       "params": node.params,
-      "helperBody": helperBody,
       "varDecl": varDecl,
+      "streamWasCanceled": js.number(error_codes.STREAM_WAS_CANCELED),
+      "errorCode": js.number(error_codes.ERROR),
+      "hasYield": analysis.hasYield,
+      "helperBody": helperBody,
       "init": generateInitializer()
     });
   }
@@ -888,7 +973,7 @@
     }
   }
 
-  /// An await is translated to a call to [thenHelper]/[streamHelper].
+  /// An await is translated to a call to [asyncHelper]/[streamHelper].
   ///
   /// See the comments of [visitFun] for an example.
   @override
@@ -897,23 +982,13 @@
     int afterAwait = newLabel("returning from await.");
     withExpression(node.expression, (js.Expression value) {
       addStatement(setGotoVariable(afterAwait));
-      js.Expression errorCallback = errorHandlerLabels.isEmpty
-          ? new js.LiteralNull()
-          : js.js("""
-            function($errorName) {
-              $gotoName = #currentHandler;
-              $helperName($errorName);
-            }""", {"currentHandler": currentErrorHandler});
-
       addStatement(js.js.statement("""
-          return #thenHelper(#value,
-                             $helperName,
-                             ${isAsync ? completerName : controllerName},
-                             #errorCallback);
+          return #asyncHelper(#value,
+                              $bodyName,
+                              ${isAsync ? completerName : controllerName});
           """, {
-        "thenHelper": isAsync ? thenHelper : streamHelper,
+        "asyncHelper": isAsync ? asyncHelper : streamHelper,
         "value": value,
-        "errorCallback": errorCallback
       }));
     }, store: false);
     beginLabel(afterAwait);
@@ -1073,9 +1148,8 @@
     // the jump.
     // The bottom of the stack is the label where the jump goes to.
     List<int> jumpStack = new List<int>();
-    for (js.Node node in targetsAndTries.reversed) {
-      if (node is js.Try) {
-        assert(node.finallyPart != null);
+    for (js.Node node in jumpTargets.reversed) {
+      if (finallyLabels[node] != null) {
         jumpStack.add(finallyLabels[node]);
       } else if (node == target) {
         jumpStack.add(targetLabel);
@@ -1120,9 +1194,9 @@
 
     beginLabel(startLabel);
 
-    targetsAndTries.add(node);
+    jumpTargets.add(node);
     visitStatement(node.body);
-    targetsAndTries.removeLast();
+    jumpTargets.removeLast();
 
     beginLabel(continueLabel);
     withExpression(node.condition, (js.Expression condition) {
@@ -1191,9 +1265,9 @@
             new js.Prefix("!", condition), gotoAndBreak(afterLabel)));
       }, store: false);
     }
-    targetsAndTries.add(node);
+    jumpTargets.add(node);
     visitStatement(node.body);
-    targetsAndTries.removeLast();
+    jumpTargets.removeLast();
     if (node.update != null) {
       beginLabel(continueLabel);
       visitExpressionIgnoreResult(node.update);
@@ -1294,9 +1368,9 @@
     continueLabels[node] = continueLabel;
 
     beginLabel(continueLabel);
-    targetsAndTries.add(node);
+    jumpTargets.add(node);
     visitStatement(node.body);
-    targetsAndTries.removeLast();
+    jumpTargets.removeLast();
     beginLabel(breakLabel);
   }
 
@@ -1502,13 +1576,13 @@
       }
     }
 
-    targetsAndTries.add(node);
+    jumpTargets.add(node);
     for (int i = 0; i < labels.length; i++) {
       beginLabel(labels[i]);
       visitStatement(node.cases[i].body);
     }
     beginLabel(after);
-    targetsAndTries.removeLast();
+    jumpTargets.removeLast();
   }
 
   @override
@@ -1523,12 +1597,30 @@
     }, store: false);
   }
 
-  setErrorHandler() {
+  setErrorHandler([int errorHandler]) {
     addExpressionStatement(new js.Assignment(
-        new js.VariableUse(handlerName), currentErrorHandler));
+        new js.VariableUse(handlerName),
+        errorHandler == null ? currentErrorHandler : js.number(errorHandler)));
   }
 
-  @override
+  List<int> _finalliesUpToAndEnclosingHandler() {
+    List<int> result = new List<int>();
+    for (int i = jumpTargets.length - 1; i >= 0; i--) {
+      js.Node node = jumpTargets[i];
+      int handlerLabel = handlerLabels[node];
+      if (handlerLabel != null) {
+        result.add(handlerLabel);
+        break;
+      }
+      int finallyLabel = finallyLabels[node];
+      if (finallyLabel != null) {
+        result.add(finallyLabel);
+      }
+    }
+    return result.reversed.toList();
+  }
+
+  /// See the comments of [visitFun] for more explanation.
   void visitTry(js.Try node) {
     if (!shouldTransform(node)) {
       js.Block body = translateInBlock(node.body);
@@ -1542,31 +1634,48 @@
       addStatement(new js.Try(body, catchPart, finallyPart));
       return;
     }
+
     hasTryBlocks = true;
-    int handlerLabel = newLabel("catch");
+    int uncaughtLabel = newLabel("uncaught");
+    int handlerLabel = (node.catchPart == null)
+        ? uncaughtLabel
+        : newLabel("catch");
+
     int finallyLabel = newLabel("finally");
     int afterFinallyLabel = newLabel("after finally");
-    errorHandlerLabels.add(handlerLabel);
+    if (node.finallyPart != null) {
+      finallyLabels[node.finallyPart] = finallyLabel;
+      jumpTargets.add(node.finallyPart);
+    }
+
+    handlerLabels[node] = handlerLabel;
+    jumpTargets.add(node);
+
     // Set the error handler here. It must be cleared on every path out;
     // normal and error exit.
     setErrorHandler();
-    if (node.finallyPart != null) {
-      finallyLabels[node] = finallyLabel;
-      targetsAndTries.add(node);
-    }
+
     visitStatement(node.body);
-    errorHandlerLabels.removeLast();
-    addStatement(
-        js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
+
+    js.Node last = jumpTargets.removeLast();
+    assert(last == node);
+
     if (node.finallyPart == null) {
       setErrorHandler();
       addGoto(afterFinallyLabel);
     } else {
-      // The handler is set as the first thing in the finally block.
+      // The handler is reset as the first thing in the finally block.
+      addStatement(
+          js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
       addGoto(finallyLabel);
     }
-    beginLabel(handlerLabel);
+
     if (node.catchPart != null) {
+      beginLabel(handlerLabel);
+      // [uncaughtLabel] is the handler for the code in the catch-part.
+      // It ensures that [nextName] is set up to run the right finally blocks.
+      handlerLabels[node.catchPart] = uncaughtLabel;
+      jumpTargets.add(node.catchPart);
       setErrorHandler();
       // The catch declaration name can shadow outer variables, so a fresh name
       // is needed to avoid collisions.  See Ecma 262, 3rd edition,
@@ -1576,19 +1685,46 @@
       variableRenamings
           .add(new Pair(node.catchPart.declaration.name, errorRename));
       addExpressionStatement(new js.Assignment(
-          new js.VariableUse(errorRename), new js.VariableUse(resultName)));
+          new js.VariableUse(errorRename),
+          new js.VariableUse(currentErrorName)));
       visitStatement(node.catchPart.body);
       variableRenamings.removeLast();
+      if (node.finallyPart != null) {
+        // The error has been caught, so after the finally, continue after the
+        // try.
+        addStatement(js.js.statement("$nextName = [#];",
+                                     [js.number(afterFinallyLabel)]));
+        addGoto(finallyLabel);
+      } else {
+        addGoto(afterFinallyLabel);
+      }
+      js.Node last = jumpTargets.removeLast();
+      assert(last == node.catchPart);
+    }
+
+    // The "uncaught"-handler tells the finally-block to continue with
+    // the enclosing finally-blocks until the current catch-handler.
+    beginLabel(uncaughtLabel);
+
+    List<int> enclosingFinallies = _finalliesUpToAndEnclosingHandler();
+
+    int nextLabel = enclosingFinallies.removeLast();
+    if (enclosingFinallies.isNotEmpty) {
+      // [enclosingFinallies] can be empty if there is no surrounding finally
+      // blocks. Then [nextLabel] will be [rethrowLabel].
+      addStatement(
+          js.js.statement("$nextName = #;", new js.ArrayInitializer(
+              enclosingFinallies.map(js.number).toList())));
+    }
+    if (node.finallyPart == null) {
+      // The finally-block belonging to [node] will be visited because of
+      // fallthrough. If it does not exist, add an explicit goto.
+      addGoto(nextLabel);
     }
     if (node.finallyPart != null) {
-      targetsAndTries.removeLast();
-      setErrorHandler();
-      // This belongs to the catch-part, but is only needed if there is a
-      // `finally`. Therefore it is in this branch.
-      // This is needed even if there is no explicit catch-branch, because
-      // if an exception is raised the finally part has to be run.
-      addStatement(
-          js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
+      js.Node last = jumpTargets.removeLast();
+      assert(last == node.finallyPart);
+
       beginLabel(finallyLabel);
       setErrorHandler();
       visitStatement(node.finallyPart);
@@ -1658,9 +1794,9 @@
             new js.Prefix("!", condition), gotoAndBreak(afterLabel)));
       }, store: false);
     }
-    targetsAndTries.add(node);
+    jumpTargets.add(node);
     visitStatement(node.body);
-    targetsAndTries.removeLast();
+    jumpTargets.removeLast();
     addGoto(continueLabel);
     beginLabel(afterLabel);
   }
@@ -1683,36 +1819,28 @@
   ///
   /// yield/yield* in an async* function is translated much like the `await` is
   /// translated in [visitAwait], only the object is wrapped in a
-  /// [yieldExpression]/[yieldStarExpression] to let [streamHelper] distinguish.
-  ///
-  /// Because there is no Future that can fail (as there is in await) null is
-  /// passed as the errorCallback.
+  /// [yieldExpression]/[yieldStarExpression] to let [asyncStarHelper]
+  /// distinguish them.
+  /// Also [nextWhenCanceledName] is set up to contain the finally blocks that
+  /// must be run in case the stream was canceled.
   void addAsyncYield(js.DartYield node, js.Expression expression) {
     assert(isAsyncStar);
     // Find all the finally blocks that should be performed if the stream is
     // canceled during the yield.
     // At the bottom of the stack is the return label.
     List<int> enclosingFinallyLabels = <int>[exitLabel];
-    enclosingFinallyLabels.addAll(targetsAndTries
-        .where((js.Node node) => node is js.Try)
-        .map((js.Try node) => finallyLabels[node]));
-    int destinationOnCancel = enclosingFinallyLabels.removeLast();
-    js.ArrayInitializer finallyListInitializer = new js.ArrayInitializer(
-        enclosingFinallyLabels.map(js.number).toList());
+    enclosingFinallyLabels.addAll(jumpTargets
+        .where((js.Node node) => finallyLabels[node] != null)
+        .map((js.Block node) => finallyLabels[node]));
+    addStatement(js.js.statement("$nextWhenCanceledName = #",
+        [new js.ArrayInitializer(enclosingFinallyLabels.map(js.number)
+            .toList())]));
     addStatement(js.js.statement("""
         return #streamHelper(#yieldExpression(#expression),
-            $helperName, $controllerName, function () {
-              if (#notEmptyFinallyList)
-                $nextName = #finallyList;
-              $gotoName = #destinationOnCancel;
-              $helperName();
-            });""", {
+            $bodyName, $controllerName);""", {
       "streamHelper": streamHelper,
       "yieldExpression": node.hasStar ? yieldStarExpression : yieldExpression,
       "expression": expression,
-      "notEmptyFinallyList": enclosingFinallyLabels.isNotEmpty,
-      "finallyList": finallyListInitializer,
-      "destinationOnCancel": js.number(destinationOnCancel)
     }));
   }
 
@@ -1753,6 +1881,8 @@
 
   bool hasThis = false;
 
+  bool hasYield = false;
+
   // The function currently being analyzed.
   js.Fun currentFunction;
 
@@ -2143,6 +2273,7 @@
 
   @override
   bool visitDartYield(js.DartYield node) {
+    hasYield = true;
     visit(node.expression);
     return true;
   }
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index e396899..4f77f85 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -1600,8 +1600,8 @@
     return findHelper("throwCyclicInit");
   }
 
-  Element getThenHelper() {
-    return findHelper("thenHelper");
+  Element getAsyncHelper() {
+    return findHelper("asyncHelper");
   }
 
   Element getYieldStar() {
@@ -1616,8 +1616,14 @@
     return classElement.lookupLocalMember("yieldSingle");
   }
 
-  Element getStreamHelper() {
-    return findHelper("streamHelper");
+  Element getSyncStarUncaughtError() {
+    ClassElement classElement = findHelper("IterationMarker");
+    classElement.ensureResolved(compiler);
+    return classElement.lookupLocalMember("uncaughtError");
+  }
+
+  Element getAsyncStarHelper() {
+    return findHelper("asyncStarHelper");
   }
 
   Element getStreamOfController() {
@@ -2405,7 +2411,7 @@
                            Enqueuer enqueuer,
                            Registry registry) {
     if (element.asyncMarker == AsyncMarker.ASYNC) {
-      enqueue(enqueuer, getThenHelper(), registry);
+      enqueue(enqueuer, getAsyncHelper(), registry);
       enqueue(enqueuer, getCompleterConstructor(), registry);
       enqueue(enqueuer, getStreamIteratorConstructor(), registry);
     } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
@@ -2413,9 +2419,10 @@
       enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
       enqueue(enqueuer, getEndOfIteration(), registry);
       enqueue(enqueuer, getYieldStar(), registry);
+      enqueue(enqueuer, getSyncStarUncaughtError(), registry);
     } else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
       enqueuer.registerInstantiatedClass(getASyncStarController(), registry);
-      enqueue(enqueuer, getStreamHelper(), registry);
+      enqueue(enqueuer, getAsyncStarHelper(), registry);
       enqueue(enqueuer, getStreamOfController(), registry);
       enqueue(enqueuer, getYieldSingle(), registry);
       enqueue(enqueuer, getYieldStar(), registry);
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 13350ca..1d4a274 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -25,12 +25,13 @@
       JavaScriptBackend backend = builder.backend;
 
       AsyncRewriter rewriter = null;
+
       if (element.asyncMarker == AsyncMarker.ASYNC) {
         rewriter = new AsyncRewriter(
             backend.compiler,
             backend.compiler.currentElement,
-            thenHelper:
-                backend.emitter.staticFunctionAccess(backend.getThenHelper()),
+            asyncHelper:
+                backend.emitter.staticFunctionAccess(backend.getAsyncHelper()),
             newCompleter: backend.emitter.staticFunctionAccess(
                 backend.getCompleterConstructor()),
             safeVariableName: backend.namer.safeVariableName);
@@ -44,6 +45,8 @@
                 backend.getSyncStarIterableConstructor()),
             yieldStarExpression: backend.emitter.staticFunctionAccess(
                 backend.getYieldStar()),
+            uncaughtErrorExpression: backend.emitter.staticFunctionAccess(
+                backend.getSyncStarUncaughtError()),
             safeVariableName: backend.namer.safeVariableName);
       }
       else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
@@ -51,7 +54,7 @@
             backend.compiler,
             backend.compiler.currentElement,
             streamHelper: backend.emitter.staticFunctionAccess(
-                backend.getStreamHelper()),
+                backend.getAsyncStarHelper()),
             streamOfController: backend.emitter.staticFunctionAccess(
                 backend.getStreamOfController()),
             newController: backend.emitter.staticFunctionAccess(
@@ -1058,6 +1061,13 @@
   // We build the Ssa graph by simulating a stack machine.
   List<HInstruction> stack = <HInstruction>[];
 
+  /// Returns `true` if the current element is an `async` function.
+  bool get isBuildingAsyncFunction {
+    Element element = sourceElement;
+    return (element is FunctionElement &&
+            element.asyncMarker == AsyncMarker.ASYNC);
+  }
+
   SsaBuilder(JavaScriptBackend backend,
              CodegenWorkItem work,
              this.nativeEmitter,
@@ -5179,6 +5189,28 @@
     emitReturn(value, node);
   }
 
+  /// Returns true if the [type] is a valid return type for an asynchronous
+  /// function.
+  ///
+  /// Asynchronous functions return a `Future`, and a valid return is thus
+  /// either dynamic, Object, or Future.
+  ///
+  /// We do not accept the internal Future implementation class.
+  bool isValidAsyncReturnType(DartType type) {
+    assert (isBuildingAsyncFunction);
+    // TODO(sigurdm): In an internal library a function could be declared:
+    //
+    // _FutureImpl foo async => 1;
+    //
+    // This should be valid (because the actual value returned from an async
+    // function is a `_FutureImpl`), but currently false is returned in this
+    // case.
+    return type.isDynamic ||
+           type.isObject ||
+           (type is InterfaceType &&
+               type.element == compiler.futureClass);
+  }
+
   visitReturn(ast.Return node) {
     if (identical(node.beginToken.stringValue, 'native')) {
       native.handleSsaNative(this, node.expression);
@@ -5190,7 +5222,19 @@
     } else {
       visit(node.expression);
       value = pop();
-      value = potentiallyCheckOrTrustType(value, returnType);
+      if (isBuildingAsyncFunction) {
+        if (compiler.enableTypeAssertions &&
+            !isValidAsyncReturnType(returnType)) {
+          String message =
+                "Async function returned a Future, "
+                "was declared to return a $returnType.";
+          generateTypeError(node, message);
+          pop();
+          return;
+        }
+      } else {
+        value = potentiallyCheckOrTrustType(value, returnType);
+      }
     }
 
     handleInTryStatement();
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index c89a8ce..3d05dc8 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -711,6 +711,12 @@
       indexRange = info.newUnboundRange();
       assert(!check.index.isInteger(compiler));
     }
+    if (lengthRange == null) {
+      // We might have lost the length range due to a type conversion that
+      // asserts a non-integer type. In such a case, the program will never
+      // get to this point anyway, so no need to try and refine ranges.
+      return indexRange;
+    }
     assert(check.length.isInteger(compiler));
 
     // Check if the index is strictly below the upper bound of the length
diff --git a/sdk/bin/pub b/sdk/bin/pub
index 8427727..1fd6864 100755
--- a/sdk/bin/pub
+++ b/sdk/bin/pub
@@ -29,10 +29,6 @@
 unset VM_OPTIONS
 declare -a VM_OPTIONS
 
-# Give the VM extra memory for dart2js.
-# TODO(rnystrom): Remove when #8355 is fixed.
-VM_OPTIONS+=("--old_gen_heap_size=1024")
-
 # Allow extra VM options to be passed in through an environment variable.
 if [[ $DART_VM_OPTIONS ]]; then
   read -a OPTIONS <<< "$DART_VM_OPTIONS"
diff --git a/sdk/bin/pub.bat b/sdk/bin/pub.bat
index 4b8b85d..98d5420 100644
--- a/sdk/bin/pub.bat
+++ b/sdk/bin/pub.bat
@@ -23,11 +23,6 @@
 
 set VM_OPTIONS=
 
-rem Give the VM extra memory for dart2js.
-rem # TODO(rnystrom): Remove when #8355 is fixed.
-rem See comments regarding options below in dart2js shell script.
-set VM_OPTIONS=%VM_OPTIONS% --old_gen_heap_size=1024
-
 rem Use the Dart binary in the built SDK so pub can find the version file next
 rem to it.
 set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index b170538..49107bc 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -4,6 +4,8 @@
 
 library _js_helper;
 
+import 'dart:_async_await_error_codes' as async_error_codes;
+
 import 'dart:_js_embedded_names' show
     GET_TYPE_FROM_NAME,
     GET_ISOLATE_TAG,
@@ -26,13 +28,13 @@
     leaveJsAsync;
 
 import 'dart:async' show
-  Future,
-  DeferredLoadException,
-  Completer,
-  StreamController,
-  Stream,
-  StreamSubscription,
-  scheduleMicrotask;
+    Future,
+    DeferredLoadException,
+    Completer,
+    StreamController,
+    Stream,
+    StreamSubscription,
+    scheduleMicrotask;
 
 import 'dart:_foreign_helper' show
     DART_CLOSURE_TO_JS,
@@ -3477,59 +3479,62 @@
 ///
 /// If [object] is not a future it will be wrapped in a `new Future.value`.
 ///
-/// If [helperCallback] is null it indicates a return from the async function,
-/// and we complete the completer with object.
+/// If [asyncBody] is [async_error_codes.SUCCESS]/[async_error_codes.ERROR] it
+/// indicates a return or throw from the async function, and
+/// complete/completeError is called on [completer] with [object].
 ///
-/// Otherwise [helperCallback] is set up to be called when the future is
-/// successfull and [errorCallback] if it is completed with an error.
-///
-/// If helperCallback or errorCallback throws we complete the completer with the
-/// error.
+/// Otherwise [asyncBody] is set up to be called when the future is completed
+/// with a code [async_error_codes.SUCCESS]/[async_error_codes.ERROR] depending
+/// on the success of the future.
 ///
 /// Returns the future of the completer for convenience of the first call.
-dynamic thenHelper(dynamic object,
-                   dynamic /* js function */ helperCallback,
-                   Completer completer,
-                   dynamic /* js function */ errorCallback) {
-  if (helperCallback == null) {
+dynamic asyncHelper(dynamic object,
+                    dynamic /* js function */ bodyFunctionOrErrorCode,
+                    Completer completer) {
+  if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
     completer.complete(object);
     return;
+  } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+    // The error is a js-error.
+    completer.completeError(unwrapException(object),
+                            getTraceFromException(object));
+    return;
   }
   Future future = object is Future ? object : new Future.value(object);
-  future.then(_wrapJsFunctionForThenHelper(helperCallback, completer),
-              onError: (errorCallback == null)
-                  ? null
-                  : _wrapJsFunctionForThenHelper(errorCallback, completer));
+  future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+                                      async_error_codes.SUCCESS),
+      onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+                                       async_error_codes.ERROR));
   return completer.future;
 }
 
-Function _wrapJsFunctionForThenHelper(dynamic /* js function */ function,
-                                      Completer completer) {
+Function _wrapJsFunctionForAsync(dynamic /* js function */ function,
+                                 int errorCode) {
   return (result) {
-    try {
-      JS('', '#(#)', function, result);
-    } catch (e, st) {
-      completer.completeError(e, st);
-    }
+    JS('', '#(#, #)', function, errorCode, result);
   };
 }
 
-
 /// Implements the runtime support for async* functions.
 ///
 /// Called by the transformed function for each original return, await, yield,
 /// yield* and before starting the function.
 ///
-/// When the async* function wants to return it calls this function. with
-/// [helperCallback] == null, the streamHelper takes this as signal to close the
-/// stream.
+/// When the async* function wants to return it calls this function with
+/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
+/// as signal to close the stream.
 ///
-/// If the async* function wants to do a yield or yield* it calls this function
-/// with [object] being an [IterationMarker]. In this case [errorCallback] has a
-/// special meaning; it is a callback that will run all enclosing finalizers.
+/// When the async* function wants to signal that an uncaught error was thrown,
+/// it calls this function with [asyncBody] == [async_error_codes.ERROR],
+/// the streamHelper takes this as signal to addError [object] to the
+/// [controller] and close it.
+///
+/// If the async* function wants to do a yield or yield*, it calls this function
+/// with [object] being an [IterationMarker].
 ///
 /// In the case of a yield or yield*, if the stream subscription has been
-/// canceled [errorCallback] is scheduled.
+/// canceled, schedules [asyncBody] to be called with
+/// [async_error_codes.STREAM_WAS_CANCELED].
 ///
 /// If [object] is a single-yield [IterationMarker], adds the value of the
 /// [IterationMarker] to the stream. If the stream subscription has been
@@ -3539,30 +3544,32 @@
 /// If [object] is a yield-star [IterationMarker], starts listening to the
 /// yielded stream, and adds all events and errors to our own controller (taking
 /// care if the subscription has been paused or canceled) - when the sub-stream
-/// is done, schedules [helperCallback] again.
+/// is done, schedules [asyncBody] again.
 ///
 /// If the async* function wants to do an await it calls this function with
 /// [object] not and [IterationMarker].
 ///
 /// If [object] is not a [Future], it is wrapped in a `Future.value`.
-/// The [helperCallback] is called on successfull completion of the
-/// future.
-///
-/// If [helperCallback] or [errorCallback] throws the error is added to the
-/// stream.
-void streamHelper(dynamic object,
-                     dynamic /* js function */ helperCallback,
-                     AsyncStarStreamController controller,
-                     dynamic /* js function */ errorCallback) {
-  if (helperCallback == null) {
+/// The [asyncBody] is called on completion of the future (see [asyncHelper].
+void asyncStarHelper(dynamic object,
+                     dynamic /* int | js function */ bodyFunctionOrErrorCode,
+                     AsyncStarStreamController controller) {
+  if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
     // This happens on return from the async* function.
     controller.close();
     return;
+  } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+    // The error is a js-error.
+    controller.addError(unwrapException(object),
+                        getTraceFromException(object));
+    controller.close();
+    return;
   }
 
   if (object is IterationMarker) {
     if (controller.stopRunning) {
-      _wrapJsFunctionForStream(errorCallback, controller)();
+      _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+          async_error_codes.STREAM_WAS_CANCELED)(null);
       return;
     }
     if (object.state == IterationMarker.YIELD_SINGLE) {
@@ -3573,7 +3580,9 @@
       }
       // TODO(sigurdm): We should not suspend here according to the spec.
       scheduleMicrotask(() {
-          _wrapJsFunctionForStream(helperCallback, controller)(null);
+        _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+                                async_error_codes.SUCCESS)
+            (null);
       });
       return;
     } else if (object.state == IterationMarker.YIELD_STAR) {
@@ -3584,17 +3593,18 @@
       // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
       controller.addStream(stream).then((_) {
         controller.isAdding = false;
-        _wrapJsFunctionForStream(helperCallback, controller)(null);
+        _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+                                async_error_codes.SUCCESS)(null);
       });
       return;
     }
   }
 
   Future future = object is Future ? object : new Future.value(object);
-  future.then(_wrapJsFunctionForStream(helperCallback, controller),
-              onError: errorCallback == null
-                  ? null
-                  : _wrapJsFunctionForStream(errorCallback, controller));
+  future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+                                      async_error_codes.SUCCESS),
+              onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+                                               async_error_codes.ERROR));
 }
 
 Stream streamOfController(AsyncStarStreamController controller) {
@@ -3622,11 +3632,13 @@
   AsyncStarStreamController(helperCallback) {
     controller = new StreamController(
       onListen: () {
-        scheduleMicrotask(() => JS('', '#(null)', helperCallback));
+        scheduleMicrotask(() {
+          JS('', '#(#, null)', helperCallback, async_error_codes.SUCCESS);
+        });
       },
       onResume: () {
         if (!isAdding) {
-          streamHelper(null, helperCallback, this, null);
+          asyncStarHelper(null, helperCallback, this);
         }
       }, onCancel: () {
         stopRunning = true;
@@ -3638,22 +3650,11 @@
   return new AsyncStarStreamController(helperCallback);
 }
 
-Function _wrapJsFunctionForStream(dynamic /* js function */ function,
-                                  AsyncStarStreamController controller) {
-  return (result) {
-    try {
-      JS('', '#(#)', function, result);
-    } catch (e, st) {
-      controller.addError(e, st);
-    }
-  };
-}
-
-
 class IterationMarker {
   static const YIELD_SINGLE = 0;
   static const YIELD_STAR = 1;
   static const ITERATION_ENDED = 2;
+  static const UNCAUGHT_ERROR = 3;
 
   final value;
   final int state;
@@ -3672,11 +3673,15 @@
     return new IterationMarker._(YIELD_SINGLE, value);
   }
 
+  static uncaughtError(dynamic error) {
+    return new IterationMarker._(UNCAUGHT_ERROR, error);
+  }
+
   toString() => "IterationMarker($state, $value)";
 }
 
 class SyncStarIterator implements Iterator {
-  final Function _helper;
+  final Function _body;
 
   // If [runningNested] this is the nested iterator, otherwise it is the
   // current value.
@@ -3685,8 +3690,8 @@
 
   get current => _runningNested ? _current.current : _current;
 
-  SyncStarIterator(helper)
-      : _helper = ((arg) => JS('', '#(#)', helper, arg));
+  SyncStarIterator(body)
+      : _body = (() => JS('', '#()', body));
 
   bool moveNext() {
     if (_runningNested) {
@@ -3696,12 +3701,16 @@
         _runningNested = false;
       }
     }
-    _current = _helper(null);
+    _current = _body();
     if (_current is IterationMarker) {
       if (_current.state == IterationMarker.ITERATION_ENDED) {
         _current = null;
-        // Rely on [_helper] to repeatedly return `ITERATION_ENDED`.
+        // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
         return false;
+      } else if (_current.state == IterationMarker.UNCAUGHT_ERROR) {
+        // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
+        // This is a wrapped exception, so we use JavaScript throw to throw it.
+        JS('', 'throw #', _current.value);
       } else {
         assert(_current.state == IterationMarker.YIELD_STAR);
         _current = _current.value.iterator;
@@ -3720,7 +3729,7 @@
   // This is a function that will return a helper function that does the
   // iteration of the sync*.
   //
-  // Each invocation should give a helper with fresh state.
+  // Each invocation should give a body with fresh state.
   final dynamic /* js function */ _outerHelper;
 
   SyncStarIterable(this._outerHelper);
diff --git a/sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart b/sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart
new file mode 100644
index 0000000..f87406b
--- /dev/null
+++ b/sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart
@@ -0,0 +1,10 @@
+// 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.
+
+/// Contains error codes that transformed async/async* functions use to
+/// communicate with js_helper functions.
+
+const int SUCCESS = 0;
+const int ERROR = 1;
+const int STREAM_WAS_CANCELED = 2;
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 7594c93..938c389 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -211,6 +211,12 @@
       documented: false,
       platforms: DART2JS_PLATFORM),
 
+  "_async_await_error_codes": const LibraryInfo(
+      "_internal/compiler/js_lib/shared/async_await_error_codes.dart",
+      category: "Internal",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+
   "_metadata": const LibraryInfo(
       "html/html_common/metadata.dart",
       category: "Internal",
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 8a493a2..ce7fa1b 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -34,16 +34,11 @@
 
 
 /// Type of lock when requesting a lock on a file.
-class FileLock {
-  final int _lock;
-
+enum FileLock {
   /// Shared file lock.
-  static const SHARED = const FileLock._internal(0);
-
+  SHARED,
   /// Exclusive file lock.
-  static const EXCLUSIVE = const FileLock._internal(1);
-
-  const FileLock._internal(this._lock);
+  EXCLUSIVE
 }
 
 /**
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index d00f629..101a2d6 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -222,9 +222,8 @@
    *
    * If an IP version 6 (IPv6) address is used, both IP version 6
    * (IPv6) and version 4 (IPv4) connections will be accepted. To
-   * restrict this to version 6 (IPv6) only, use [HttpServer.listenOn]
-   * with a [ServerSocket] configured for IP version 6 connections
-   * only.
+   * restrict this to version 6 (IPv6) only, use [v6Only] to set
+   * version 6 only.
    *
    * If [port] has the value [:0:] an ephemeral port will be chosen by
    * the system. The actual port used can be retrieved using the
@@ -234,11 +233,21 @@
    * backlog for the underlying OS listen setup. If [backlog] has the
    * value of [:0:] (the default) a reasonable value will be chosen by
    * the system.
+   *
+   * The optional argument [shared] specify whether additional binds
+   * to the same `address`, `port` and `v6Only` combination is
+   * possible from the same Dart process. If `shared` is `true` and
+   * additional binds are performed, then the incoming connections
+   * will be distributed between that set of `HttpServer`s. One way of
+   * using this is to have number of isolates between which incoming
+   * connections are distributed.
    */
   static Future<HttpServer> bind(address,
                                  int port,
-                                 {int backlog: 0})
-      => _HttpServer.bind(address, port, backlog);
+                                 {int backlog: 0,
+                                  bool v6Only: false,
+                                  bool shared: false})
+      => _HttpServer.bind(address, port, backlog, v6Only, shared);
 
   /**
    * The [address] can either be a [String] or an
@@ -254,9 +263,8 @@
    *
    * If an IP version 6 (IPv6) address is used, both IP version 6
    * (IPv6) and version 4 (IPv4) connections will be accepted. To
-   * restrict this to version 6 (IPv6) only, use [HttpServer.listenOn]
-   * with a [ServerSocket] configured for IP version 6 connections
-   * only.
+   * restrict this to version 6 (IPv6) only, use [v6Only] to set
+   * version 6 only.
    *
    * If [port] has the value [:0:] an ephemeral port will be chosen by
    * the system. The actual port used can be retrieved using the
@@ -271,18 +279,30 @@
    * is looked up in the certificate database, and is used as the server
    * certificate. If [requestClientCertificate] is true, the server will
    * request clients to authenticate with a client certificate.
+   *
+   * The optional argument [shared] specify whether additional binds
+   * to the same `address`, `port` and `v6Only` combination is
+   * possible from the same Dart process. If `shared` is `true` and
+   * additional binds are performed, then the incoming connections
+   * will be distributed between that set of `HttpServer`s. One way of
+   * using this is to have number of isolates between which incoming
+   * connections are distributed.
    */
 
   static Future<HttpServer> bindSecure(address,
                                        int port,
                                        {int backlog: 0,
+                                        bool v6Only: false,
                                         String certificateName,
-                                        bool requestClientCertificate: false})
+                                        bool requestClientCertificate: false,
+                                        bool shared: false})
       => _HttpServer.bindSecure(address,
                                 port,
                                 backlog,
+                                v6Only,
                                 certificateName,
-                                requestClientCertificate);
+                                requestClientCertificate,
+                                shared);
 
   /**
    * Attaches the HTTP server to an existing [ServerSocket]. When the
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 846cd6b..dd03aeb 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -2160,26 +2160,33 @@
   Duration _idleTimeout;
   Timer _idleTimer;
 
-  static Future<HttpServer> bind(address, int port, int backlog) {
-    return ServerSocket.bind(address, port, backlog: backlog).then((socket) {
-      return new _HttpServer._(socket, true);
-    });
+  static Future<HttpServer> bind(
+      address, int port, int backlog, bool v6Only, bool shared) {
+    return ServerSocket.bind(
+        address, port, backlog: backlog, v6Only: v6Only, shared: shared)
+            .then((socket) {
+              return new _HttpServer._(socket, true);
+            });
   }
 
   static Future<HttpServer> bindSecure(address,
                                        int port,
                                        int backlog,
+                                       bool v6Only,
                                        String certificate_name,
-                                       bool requestClientCertificate) {
+                                       bool requestClientCertificate,
+                                       bool shared) {
     return SecureServerSocket.bind(
         address,
         port,
         certificate_name,
         backlog: backlog,
-        requestClientCertificate: requestClientCertificate)
-        .then((socket) {
-          return new _HttpServer._(socket, true);
-        });
+        v6Only: v6Only,
+        requestClientCertificate: requestClientCertificate,
+        shared: shared)
+            .then((socket) {
+              return new _HttpServer._(socket, true);
+            });
   }
 
   _HttpServer._(this._serverSocket, this._closeServer) {
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index 2a73418..c987a48 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -58,6 +58,14 @@
    * To check whether a client certificate was received, check
    * SecureSocket.peerCertificate after connecting.  If no certificate
    * was received, the result will be null.
+   *
+   * The optional argument [shared] specify whether additional binds
+   * to the same `address`, `port` and `v6Only` combination is
+   * possible from the same Dart process. If `shared` is `true` and
+   * additional binds are performed, then the incoming connections
+   * will be distributed between that set of
+   * `SecureServerSocket`s. One way of using this is to have number of
+   * isolates between which incoming connections are distributed.
    */
   static Future<SecureServerSocket> bind(
       address,
@@ -185,6 +193,14 @@
    * need to specify both.  To check whether a client certificate was received,
    * check SecureSocket.peerCertificate after connecting.  If no certificate
    * was received, the result will be null.
+   *
+   * The optional argument [shared] specify whether additional binds
+   * to the same `address`, `port` and `v6Only` combination is
+   * possible from the same Dart process. If `shared` is `true` and
+   * additional binds are performed, then the incoming connections
+   * will be distributed between that set of
+   * `RawSecureServerSocket`s. One way of using this is to have number
+   * of isolates between which incoming connections are distributed.
    */
   static Future<RawSecureServerSocket> bind(
       address,
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 08f973e..d703c8d 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -223,6 +223,14 @@
    * backlog for the underlying OS listen setup. If [backlog] has the
    * value of [:0:] (the default) a reasonable value will be chosen by
    * the system.
+   *
+   * The optional argument [shared] specify whether additional binds
+   * to the same `address`, `port` and `v6Only` combination is
+   * possible from the same Dart process. If `shared` is `true` and
+   * additional binds are performed, then the incoming connections
+   * will be distributed between that set of `RawServerSocket`s. One
+   * way of using this is to have number of isolates between which
+   * incoming connections are distributed.
    */
   external static Future<RawServerSocket> bind(address,
                                                int port,
@@ -249,8 +257,9 @@
   /**
    * Get the [RawServerSocketReference].
    *
-   * WARNING: This feature is *highly experimental* and currently only works on
-   * Linux. The API is most likely going to change in the near future.
+   * WARNING: This feature is *highly experimental* and currently only
+   * works on Linux. The API will be removed in Dart 1.10. Use the
+   * `shared` optional argument on the `bind` method instead.
    *
    * The returned [RawServerSocketReference] can be used to create other
    * [RawServerSocket]s listening on the same port,
@@ -260,6 +269,9 @@
    * The [RawServerSocketReference] can be distributed to other isolates through
    * a [RawSendPort].
    */
+
+  @Deprecated('This will be removed in Dart 1.10. Use the '
+              '`shared` optional argument on the `bind` method instead.')
   RawServerSocketReference get reference;
 }
 
@@ -270,6 +282,7 @@
  * WARNING: This class is used with [RawServerSocket.reference] which is highly
  * experimental.
  */
+@Deprecated('This will be removed in Dart 1.10.')
 abstract class RawServerSocketReference {
   /**
    * Create a new [RawServerSocket], from this reference.
@@ -315,6 +328,14 @@
    * backlog for the underlying OS listen setup. If [backlog] has the
    * value of [:0:] (the default) a reasonable value will be chosen by
    * the system.
+   *
+   * The optional argument [shared] specify whether additional binds
+   * to the same `address`, `port` and `v6Only` combination is
+   * possible from the same Dart process. If `shared` is `true` and
+   * additional binds are performed, then the incoming connections
+   * will be distributed between that set of `ServerSocket`s. One way
+   * of using this is to have number of isolates between which
+   * incoming connections are distributed.
    */
   external static Future<ServerSocket> bind(address,
                                             int port,
@@ -341,8 +362,9 @@
   /**
    * Get the [ServerSocketReference].
    *
-   * WARNING: This feature is *highly experimental* and currently only works on
-   * Linux. The API is most likely going to change in the near future.
+   * WARNING: This feature is *highly experimental* and currently only
+   * works on Linux. The API will be removed in Dart 1.10. Use the
+   * `shared` optional argument on the `bind` method instead.
    *
    * The returned [ServerSocketReference] can be used to create other
    * [ServerSocket]s listening on the same port,
@@ -352,6 +374,8 @@
    * The [ServerSocketReference] can be distributed to other isolates through a
    * [SendPort].
    */
+  @Deprecated('This will be removed in Dart 1.10. Use the '
+              '`shared` optional argument on the `bind` method instead.')
   ServerSocketReference get reference;
 }
 
@@ -362,6 +386,7 @@
  * WARNING: This class is used with [ServerSocket.reference] which is highly
  * experimental.
  */
+@Deprecated('This will be removed in Dart 1.10.')
 abstract class ServerSocketReference {
   /**
    * Create a new [ServerSocket], from this reference.
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index a9a64c2..49362dc 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -257,15 +257,6 @@
 Language/15_Types/1_Static_Types_A03_t01: RuntimeError # Issue 21089
 Language/15_Types/2_Dynamic_Type_System_A01_t02: RuntimeError # Issue 21088
 Language/15_Types/8_Parameterized_Types_A03_t07: RuntimeError # Issue 21088
-LayoutTests/fast/url/file-http-base_t01: Crash # Issue 21166
-LayoutTests/fast/url/file_t01: Crash # Issue 21166
-LayoutTests/fast/url/relative-unix_t01: Crash # Issue 21166
-LayoutTests/fast/url/relative-win_t01: Crash # Issue 21166
-LayoutTests/fast/url/relative_t01: Crash # Issue 21166
-LayoutTests/fast/url/segments-from-data-url_t01: Crash # Issue 21166
-LayoutTests/fast/url/segments_t01: Crash # Issue 21166
-LayoutTests/fast/url/trivial-segments_t01: Crash # Issue 21166
-LayoutTests/fast/url/trivial_t01: Crash # Issue 21166
 LibTest/core/Map/Map_class_A01_t04: Slow, Pass
 LibTest/core/Uri/Uri_A06_t03: Slow, Pass
 LibTest/math/Point/operator_mult_A02_t01: RuntimeError # Issue 1533
diff --git a/tests/compiler/dart2js/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await_js_transform_test.dart
index 1006186..98bcbe3 100644
--- a/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -13,14 +13,15 @@
   Fun rewritten = new AsyncRewriter(
       null, // The diagnostic helper should not be used in these tests.
       null,
-      thenHelper: new VariableUse("thenHelper"),
+      asyncHelper: new VariableUse("thenHelper"),
       newCompleter: new VariableUse("Completer"),
       endOfIteration: new VariableUse("endOfIteration"),
       newIterable: new VariableUse("Iterator"),
       safeVariableName: (String name) => "__$name").rewrite(fun);
- 
+
   JavaScriptPrintingOptions options = new JavaScriptPrintingOptions();
-  JavaScriptPrintingContext context = new SimpleJavaScriptPrintingContext();
+  SimpleJavaScriptPrintingContext context =
+      new SimpleJavaScriptPrintingContext();
   Printer printer = new Printer(options, context);
   printer.visit(rewritten);
   Expect.stringEquals(expected, context.getText());
@@ -28,31 +29,44 @@
 
 main() {
   testTransform("""
-function() async {
+function(a) async {
   print(this.x); // Ensure `this` is translated in the helper function.
   await foo();
 }""", """
-function() {
-  var __goto = 0, __completer = new Completer(), __self = this;
-  function __helper(__result) {
+function(a) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __self = this;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-          print(__self.x);
-          __goto = 1;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 1:
-          // returning from await.
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+            print(__self.x);
+            __goto = 2;
+            return thenHelper(foo(), __body, __completer);
+          case 2:
+            // returning from await.
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
 
   testTransform("""
-function() async {
+function(b) async {
   try {
     __outer: while (true) { // Overlapping label name.
       try {
@@ -75,87 +89,86 @@
   }
   return 4;
 }""", """
-function() {
-  var __goto = 0, __completer = new Completer(), __handler = null, __next, __returnValue, __helper;
-  function __helper1(__result) {
+function(b) {
+  var __goto = 0, __completer = new Completer(), __handler = 2, __currentError, __next, __returnValue, __helper;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
       try {
         __outer1:
           switch (__goto) {
             case 0:
               // Function start
-              __handler = 2;
-            case 6:
-              // continue __outer
+              __handler = 3;
             case 7:
+              // continue __outer
+            case 8:
               // while condition
-              __handler = 9;
+              __handler = 10;
               inner: {
                 while (true) {
-                  __next = [5];
+                  __next = [6];
                   // goto finally
-                  __goto = 10;
+                  __goto = 11;
                   break __outer1;
                   break;
                 }
               }
               while (true) {
-                __next = [1, 3];
+                __next = [1, 4];
                 // goto finally
-                __goto = 10;
+                __goto = 11;
                 break __outer1;
               }
-              __goto = 12;
-              return thenHelper(foo(), __helper1, __completer, function(__error) {
-                __goto = 9;
-                __helper1(__error);
-              });
-            case 12:
+              __goto = 13;
+              return thenHelper(foo(), __body, __completer);
+            case 13:
               // returning from await.
               __helper = __result;
-              __next = [11];
+              __next = [12];
               // goto finally
-              __goto = 10;
+              __goto = 11;
               break;
-            case 9:
-              // catch
-              __handler = 2;
-              __next = [11];
             case 10:
+              // uncaught
+              __next = [3];
+            case 11:
               // finally
-              __handler = 2;
+              __handler = 3;
               foo();
               // goto while condition
-              __goto = 7;
+              __goto = 8;
               break;
               __returnValue = 2;
               __next = [1];
               // goto finally
-              __goto = 3;
+              __goto = 4;
               break;
               // goto the next finally handler
               __goto = __next.pop();
               break;
-            case 11:
+            case 12:
               // after finally
               // goto while condition
-              __goto = 7;
+              __goto = 8;
               break;
-            case 8:
+            case 9:
               // after while
-            case 5:
+            case 6:
               // break __outer
-              __next = [4];
+              __next = [5];
               // goto finally
-              __goto = 3;
+              __goto = 4;
               break;
-            case 2:
-              // catch
-              __handler = null;
-              __next = [4];
             case 3:
+              // uncaught
+              __next = [2];
+            case 4:
               // finally
-              __handler = null;
+              __handler = 2;
               __returnValue = 3;
               // goto return
               __goto = 1;
@@ -163,7 +176,7 @@
               // goto the next finally handler
               __goto = __next.pop();
               break;
-            case 4:
+            case 5:
               // after finally
               __returnValue = 4;
               // goto return
@@ -171,20 +184,22 @@
               break;
             case 1:
               // return
-              return thenHelper(__returnValue, null, __completer, null);
+              return thenHelper(__returnValue, 0, __completer, null);
+            case 2:
+              // rethrow
+              return thenHelper(__currentError, 1, __completer);
           }
       } catch (__error) {
-        if (__handler === null)
-          throw __error;
-        __result = __error;
+        __currentError = __error;
         __goto = __handler;
       }
 
   }
-  return thenHelper(null, __helper1, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
-function() async {
+function(c) async {
   var a, b, c, d, e, f;
   a = b++; // post- and preincrements.
   b = --b;
@@ -193,45 +208,59 @@
   e = foo1()[await foo2()]--;
   f = --foo1()[await foo2()];
 }""", """
-function() {
-  var __goto = 0, __completer = new Completer(), a, b, c, d, e, f, __temp1;
-  function __helper(__result) {
+function(c) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, a, b, c, d, e, f, __temp1;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-          a = b++;
-          b = --b;
-          __goto = 1;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 1:
-          // returning from await.
-          c = __result.a++;
-          __goto = 2;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 2:
-          // returning from await.
-          d = ++__result.a;
-          __temp1 = foo1();
-          __goto = 3;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 3:
-          // returning from await.
-          e = __temp1[__result]--;
-          __temp1 = foo1();
-          __goto = 4;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 4:
-          // returning from await.
-          f = --__temp1[__result];
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+            a = b++;
+            b = --b;
+            __goto = 2;
+            return thenHelper(foo(), __body, __completer);
+          case 2:
+            // returning from await.
+            c = __result.a++;
+            __goto = 3;
+            return thenHelper(foo(), __body, __completer);
+          case 3:
+            // returning from await.
+            d = ++__result.a;
+            __temp1 = foo1();
+            __goto = 4;
+            return thenHelper(foo2(), __body, __completer);
+          case 4:
+            // returning from await.
+            e = __temp1[__result]--;
+            __temp1 = foo1();
+            __goto = 5;
+            return thenHelper(foo2(), __body, __completer);
+          case 5:
+            // returning from await.
+            f = --__temp1[__result];
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
-function() async {
+function(d2) async {
   var a, b, c, d, e, f, g, h; // empty initializer
   a = foo1() || await foo2(); // short circuiting operators
   b = await foo1() || foo2();
@@ -242,119 +271,133 @@
   g = await foo1() && await foo2();
   h = foo1() && foo2();
 }""", """
-function() {
-  var __goto = 0, __completer = new Completer(), a, b, c, d, e, f, g, h, __temp1;
-  function __helper(__result) {
+function(d2) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, a, b, c, d, e, f, g, h, __temp1;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-          __temp1 = foo1();
-          if (__temp1) {
-            // goto then
-            __goto = 1;
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+            __temp1 = foo1();
+            if (__temp1) {
+              // goto then
+              __goto = 2;
+              break;
+            } else
+              __result = __temp1;
+            // goto join
+            __goto = 3;
             break;
-          } else
-            __result = __temp1;
-          // goto join
-          __goto = 2;
-          break;
-        case 1:
-          // then
-          __goto = 3;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 3:
-          // returning from await.
-        case 2:
-          // join
-          a = __result;
-          __goto = 4;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 4:
-          // returning from await.
-          b = __result || foo2();
-          __goto = 7;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 7:
-          // returning from await.
-          __temp1 = __result;
-          if (__temp1) {
-            // goto then
+          case 2:
+            // then
+            __goto = 4;
+            return thenHelper(foo2(), __body, __completer);
+          case 4:
+            // returning from await.
+          case 3:
+            // join
+            a = __result;
             __goto = 5;
+            return thenHelper(foo1(), __body, __completer);
+          case 5:
+            // returning from await.
+            b = __result || foo2();
+            __goto = 8;
+            return thenHelper(foo1(), __body, __completer);
+          case 8:
+            // returning from await.
+            __temp1 = __result;
+            if (__temp1) {
+              // goto then
+              __goto = 6;
+              break;
+            } else
+              __result = __temp1;
+            // goto join
+            __goto = 7;
             break;
-          } else
-            __result = __temp1;
-          // goto join
-          __goto = 6;
-          break;
-        case 5:
-          // then
-          __temp1 = foo3;
-          __goto = 8;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 8:
-          // returning from await.
-          __result = __temp1(__result);
-        case 6:
-          // join
-          c = __result;
-          d = foo1() || foo2();
-          __temp1 = foo1();
-          if (__temp1)
-            __result = __temp1;
-          else {
-            // goto then
+          case 6:
+            // then
+            __temp1 = foo3;
             __goto = 9;
+            return thenHelper(foo2(), __body, __completer);
+          case 9:
+            // returning from await.
+            __result = __temp1(__result);
+          case 7:
+            // join
+            c = __result;
+            d = foo1() || foo2();
+            __temp1 = foo1();
+            if (__temp1)
+              __result = __temp1;
+            else {
+              // goto then
+              __goto = 10;
+              break;
+            }
+            // goto join
+            __goto = 11;
             break;
-          }
-          // goto join
-          __goto = 10;
-          break;
-        case 9:
-          // then
-          __goto = 11;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 11:
-          // returning from await.
-        case 10:
-          // join
-          e = __result;
-          __goto = 12;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 12:
-          // returning from await.
-          f = __result && foo2();
-          __goto = 15;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 15:
-          // returning from await.
-          __temp1 = __result;
-          if (__temp1)
-            __result = __temp1;
-          else {
-            // goto then
+          case 10:
+            // then
+            __goto = 12;
+            return thenHelper(foo2(), __body, __completer);
+          case 12:
+            // returning from await.
+          case 11:
+            // join
+            e = __result;
             __goto = 13;
+            return thenHelper(foo1(), __body, __completer);
+          case 13:
+            // returning from await.
+            f = __result && foo2();
+            __goto = 16;
+            return thenHelper(foo1(), __body, __completer);
+          case 16:
+            // returning from await.
+            __temp1 = __result;
+            if (__temp1)
+              __result = __temp1;
+            else {
+              // goto then
+              __goto = 14;
+              break;
+            }
+            // goto join
+            __goto = 15;
             break;
-          }
-          // goto join
-          __goto = 14;
-          break;
-        case 13:
-          // then
-          __goto = 16;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 16:
-          // returning from await.
-        case 14:
-          // join
-          g = __result;
-          h = foo1() && foo2();
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+          case 14:
+            // then
+            __goto = 17;
+            return thenHelper(foo2(), __body, __completer);
+          case 17:
+            // returning from await.
+          case 15:
+            // join
+            g = __result;
+            h = foo1() && foo2();
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
 function(x, y) async {
   while (true) {
@@ -372,75 +415,89 @@
   }
 }""", """
 function(x, y) {
-  var __goto = 0, __completer = new Completer();
-  function __helper(__result) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-        case 1:
-          // while condition
-        case 3:
-          // switch
-          switch (y) {
-            case 0:
-              // goto case
-              __goto = 5;
-              break;
-            case 1:
-              // goto case
-              __goto = 6;
-              break;
-            case 1:
-              // goto case
-              __goto = 7;
-              break;
-            case 2:
-              // goto case
-              __goto = 8;
-              break;
-          }
-          // goto after switch
-          __goto = 4;
-          break;
-        case 5:
-          // case
-        case 6:
-          // case
-          __goto = 9;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 9:
-          // returning from await.
-          // goto while condition
-          __goto = 1;
-          break;
-        case 7:
-          // case
-          __goto = 10;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 10:
-          // returning from await.
-          // goto after switch
-          __goto = 4;
-          break;
-        case 8:
-          // case
-          foo();
-        case 4:
-          // after switch
-          // goto while condition
-          __goto = 1;
-          break;
-        case 2:
-          // after while
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+          case 2:
+            // while condition
+          case 4:
+            // switch
+            switch (y) {
+              case 0:
+                // goto case
+                __goto = 6;
+                break;
+              case 1:
+                // goto case
+                __goto = 7;
+                break;
+              case 1:
+                // goto case
+                __goto = 8;
+                break;
+              case 2:
+                // goto case
+                __goto = 9;
+                break;
+            }
+            // goto after switch
+            __goto = 5;
+            break;
+          case 6:
+            // case
+          case 7:
+            // case
+            __goto = 10;
+            return thenHelper(foo(), __body, __completer);
+          case 10:
+            // returning from await.
+            // goto while condition
+            __goto = 2;
+            break;
+          case 8:
+            // case
+            __goto = 11;
+            return thenHelper(foo(), __body, __completer);
+          case 11:
+            // returning from await.
+            // goto after switch
+            __goto = 5;
+            break;
+          case 9:
+            // case
+            foo();
+          case 5:
+            // after switch
+            // goto while condition
+            __goto = 2;
+            break;
+          case 3:
+            // after while
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
-function() async {
+function(f) async {
   do {
     var a = await foo();
     if (a) // If with no awaits in body
@@ -450,51 +507,64 @@
   } while (await foo());
 }
 """, """
-function() {
-  var __goto = 0, __completer = new Completer(), a;
-  function __helper(__result) {
+function(f) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, a;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-        case 1:
-          // do body
-          __goto = 4;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 4:
-          // returning from await.
-          a = __result;
-          if (a) {
-            // goto after do
-            __goto = 3;
-            break;
-          } else {
-            // goto do condition
-            __goto = 2;
-            break;
-          }
-        case 2:
-          // do condition
-          __goto = 5;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 5:
-          // returning from await.
-          if (__result) {
-            // goto do body
-            __goto = 1;
-            break;
-          }
-        case 3:
-          // after do
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+          case 2:
+            // do body
+            __goto = 5;
+            return thenHelper(foo(), __body, __completer);
+          case 5:
+            // returning from await.
+            a = __result;
+            if (a) {
+              // goto after do
+              __goto = 4;
+              break;
+            } else {
+              // goto do condition
+              __goto = 3;
+              break;
+            }
+          case 3:
+            // do condition
+            __goto = 6;
+            return thenHelper(foo(), __body, __completer);
+          case 6:
+            // returning from await.
+            if (__result) {
+              // goto do body
+              __goto = 2;
+              break;
+            }
+          case 4:
+            // after do
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
 
   testTransform("""
-function() async {
+function(g) async {
   for (var i = 0; i < await foo1(); i += await foo2()) {
     if (foo(i))
       continue;
@@ -508,76 +578,89 @@
   } 
 }
 """, """
-function() {
-  var __goto = 0, __completer = new Completer(), __returnValue, i, __temp1;
-  function __helper(__result) {
+function(g) {
+  var __goto = 0, __completer = new Completer(), __handler = 2, __currentError, __returnValue, i, __temp1;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-          i = 0;
-        case 2:
-          // for condition
-          __temp1 = i;
-          __goto = 5;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 5:
-          // returning from await.
-          if (!(__temp1 < __result)) {
-            // goto after for
-            __goto = 4;
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+            i = 0;
+          case 3:
+            // for condition
+            __temp1 = i;
+            __goto = 6;
+            return thenHelper(foo1(), __body, __completer);
+          case 6:
+            // returning from await.
+            if (!(__temp1 < __result)) {
+              // goto after for
+              __goto = 5;
+              break;
+            }
+            if (foo(i)) {
+              // goto for update
+              __goto = 4;
+              break;
+            } else {
+              // goto after for
+              __goto = 5;
+              break;
+            }
+            __goto = !foo(i) ? 7 : 8;
             break;
-          }
-          if (foo(i)) {
-            // goto for update
+          case 7:
+            // then
+            __goto = 9;
+            return thenHelper(foo(), __body, __completer);
+          case 9:
+            // returning from await.
+            // goto return
+            __goto = 1;
+            break;
+          case 8:
+            // join
+            __temp1 = print;
+            __goto = 10;
+            return thenHelper(foo(i), __body, __completer);
+          case 10:
+            // returning from await.
+            __temp1(__result);
+          case 4:
+            // for update
+            __goto = 11;
+            return thenHelper(foo2(), __body, __completer);
+          case 11:
+            // returning from await.
+            i = __result;
+            // goto for condition
             __goto = 3;
             break;
-          } else {
-            // goto after for
-            __goto = 4;
-            break;
-          }
-          __goto = !foo(i) ? 6 : 7;
-          break;
-        case 6:
-          // then
-          __goto = 8;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 8:
-          // returning from await.
-          // goto return
-          __goto = 1;
-          break;
-        case 7:
-          // join
-          __temp1 = print;
-          __goto = 9;
-          return thenHelper(foo(i), __helper, __completer, null);
-        case 9:
-          // returning from await.
-          __temp1(__result);
-        case 3:
-          // for update
-          __goto = 10;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 10:
-          // returning from await.
-          i = __result;
-          // goto for condition
-          __goto = 2;
-          break;
-        case 4:
-          // after for
-        case 1:
-          // return
-          return thenHelper(__returnValue, null, __completer, null);
+          case 5:
+            // after for
+          case 1:
+            // return
+            return thenHelper(__returnValue, 0, __completer, null);
+          case 2:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
 
   testTransform("""
-function(a) async {
+function(a, h) async {
   var x = {"a": foo1(), "b": await foo2(), "c": foo3()};
   x["a"] = 2; // Different assignments
   (await foo()).a = 3;
@@ -586,65 +669,79 @@
   (await foo1())[await foo2()] = await foo3(6);
 }
 """, """
-function(a) {
-  var __goto = 0, __completer = new Completer(), x, __temp1, __temp2;
-  function __helper(__result) {
+function(a, h) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, x, __temp1, __temp2;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-          __temp1 = foo1();
-          __goto = 1;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 1:
-          // returning from await.
-          x = {a: __temp1, b: __result, c: foo3()};
-          x.a = 2;
-          __goto = 2;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 2:
-          // returning from await.
-          __result.a = 3;
-          __temp1 = x;
-          __goto = 3;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 3:
-          // returning from await.
-          __temp1[__result] = 4;
-          __temp1 = x;
-          __goto = 4;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 4:
-          // returning from await.
-          __temp2 = __result;
-          __goto = 5;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 5:
-          // returning from await.
-          __temp1[__temp2.a = __result] = 5;
-          __goto = 6;
-          return thenHelper(foo1(), __helper, __completer, null);
-        case 6:
-          // returning from await.
-          __temp1 = __result;
-          __goto = 7;
-          return thenHelper(foo2(), __helper, __completer, null);
-        case 7:
-          // returning from await.
-          __temp2 = __result;
-          __goto = 8;
-          return thenHelper(foo3(6), __helper, __completer, null);
-        case 8:
-          // returning from await.
-          __temp1[__temp2] = __result;
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+            __temp1 = foo1();
+            __goto = 2;
+            return thenHelper(foo2(), __body, __completer);
+          case 2:
+            // returning from await.
+            x = {a: __temp1, b: __result, c: foo3()};
+            x.a = 2;
+            __goto = 3;
+            return thenHelper(foo(), __body, __completer);
+          case 3:
+            // returning from await.
+            __result.a = 3;
+            __temp1 = x;
+            __goto = 4;
+            return thenHelper(foo(), __body, __completer);
+          case 4:
+            // returning from await.
+            __temp1[__result] = 4;
+            __temp1 = x;
+            __goto = 5;
+            return thenHelper(foo1(), __body, __completer);
+          case 5:
+            // returning from await.
+            __temp2 = __result;
+            __goto = 6;
+            return thenHelper(foo2(), __body, __completer);
+          case 6:
+            // returning from await.
+            __temp1[__temp2.a = __result] = 5;
+            __goto = 7;
+            return thenHelper(foo1(), __body, __completer);
+          case 7:
+            // returning from await.
+            __temp1 = __result;
+            __goto = 8;
+            return thenHelper(foo2(), __body, __completer);
+          case 8:
+            // returning from await.
+            __temp2 = __result;
+            __goto = 9;
+            return thenHelper(foo3(6), __body, __completer);
+          case 9:
+            // returning from await.
+            __temp1[__temp2] = __result;
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
-function(c) async {
+function(c, i) async {
   try {
     var x = c ? await foo() : foo(); // conditional
     var y = {};
@@ -659,103 +756,115 @@
   }
 }
 """, """
-function(c) {
-  var __goto = 0, __completer = new Completer(), __handler = null, x, y, __error1, __error2;
-  function __helper(__result) {
+function(c, i) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, x, y, __error1, __error2;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
       try {
         switch (__goto) {
           case 0:
             // Function start
-            __handler = 1;
-            __goto = c ? 4 : 6;
-            break;
-          case 4:
-            // then
-            __goto = 7;
-            return thenHelper(foo(), __helper, __completer, function(__error) {
-              __goto = 1;
-              __helper(__error);
-            });
-          case 7:
-            // returning from await.
-            // goto join
-            __goto = 5;
+            __handler = 3;
+            __goto = c ? 6 : 8;
             break;
           case 6:
+            // then
+            __goto = 9;
+            return thenHelper(foo(), __body, __completer);
+          case 9:
+            // returning from await.
+            // goto join
+            __goto = 7;
+            break;
+          case 8:
             // else
             __result = foo();
-          case 5:
+          case 7:
             // join
             x = __result;
             y = {};
-            __next = [3];
-            __handler = null;
+            __handler = 1;
             // goto after finally
-            __goto = 3;
+            __goto = 5;
             break;
-          case 1:
+          case 3:
             // catch
-            __handler = null;
-            __error1 = __result;
-            __handler = 8;
-            __goto = c ? 11 : 13;
+            __handler = 2;
+            __error1 = __currentError;
+            __handler = 11;
+            __goto = c ? 14 : 16;
             break;
-          case 11:
-            // then
-            __goto = 14;
-            return thenHelper(fooError(__error1), __helper, __completer, function(__error) {
-              __goto = 8;
-              __helper(__error);
-            });
           case 14:
+            // then
+            __goto = 17;
+            return thenHelper(fooError(__error1), __body, __completer);
+          case 17:
             // returning from await.
             // goto join
-            __goto = 12;
+            __goto = 15;
             break;
-          case 13:
+          case 16:
             // else
             __result = fooError(__error1);
-          case 12:
+          case 15:
             // join
             x = __result;
-            __next = [10];
+            __next = [13];
             // goto finally
-            __goto = 9;
+            __goto = 12;
             break;
-          case 8:
+          case 11:
             // catch
-            __handler = null;
-            __error2 = __result;
+            __handler = 10;
+            __error2 = __currentError;
             y.x = foo(__error2);
-            __handler = null;
-            __next = [10];
-          case 9:
+            __next = [13];
+            // goto finally
+            __goto = 12;
+            break;
+          case 10:
+            // uncaught
+            __next = [2];
+          case 12:
             // finally
-            __handler = null;
+            __handler = 2;
             foo(x);
             // goto the next finally handler
             __goto = __next.pop();
             break;
-          case 10:
+          case 13:
             // after finally
-          case 3:
+            // goto after finally
+            __goto = 5;
+            break;
+          case 2:
+            // uncaught
+            // goto rethrow
+            __goto = 1;
+            break;
+          case 5:
             // after finally
             // implicit return
-            return thenHelper(null, null, __completer, null);
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
         }
       } catch (__error) {
-        if (__handler === null)
-          throw __error;
-        __result = __error;
+        __currentError = __error;
         __goto = __handler;
       }
 
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
-function(x, y) async {
+function(x, y, j) async {
   print(await(foo(x))); // calls
   (await print)(foo(x));
   print(foo(await x));
@@ -763,57 +872,71 @@
   print(foo(x, await y, z));
 }
 """, """
-function(x, y) {
-  var __goto = 0, __completer = new Completer(), __temp1, __temp2, __temp3;
-  function __helper(__result) {
+function(x, y, j) {
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __temp1, __temp2, __temp3;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-          __temp1 = print;
-          __goto = 1;
-          return thenHelper(foo(x), __helper, __completer, null);
-        case 1:
-          // returning from await.
-          __temp1(__result);
-          __goto = 2;
-          return thenHelper(print, __helper, __completer, null);
-        case 2:
-          // returning from await.
-          __result(foo(x));
-          __temp1 = print;
-          __temp2 = foo;
-          __goto = 3;
-          return thenHelper(x, __helper, __completer, null);
-        case 3:
-          // returning from await.
-          __temp1(__temp2(__result));
-          __temp1 = print;
-          __temp2 = foo;
-          __goto = 5;
-          return thenHelper(x, __helper, __completer, null);
-        case 5:
-          // returning from await.
-          __goto = 4;
-          return thenHelper(__temp1(__temp2(__result)), __helper, __completer, null);
-        case 4:
-          // returning from await.
-          __temp1 = print;
-          __temp2 = foo;
-          __temp3 = x;
-          __goto = 6;
-          return thenHelper(y, __helper, __completer, null);
-        case 6:
-          // returning from await.
-          __temp1(__temp2(__temp3, __result, z));
-          // implicit return
-          return thenHelper(null, null, __completer, null);
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+            __temp1 = print;
+            __goto = 2;
+            return thenHelper(foo(x), __body, __completer);
+          case 2:
+            // returning from await.
+            __temp1(__result);
+            __goto = 3;
+            return thenHelper(print, __body, __completer);
+          case 3:
+            // returning from await.
+            __result(foo(x));
+            __temp1 = print;
+            __temp2 = foo;
+            __goto = 4;
+            return thenHelper(x, __body, __completer);
+          case 4:
+            // returning from await.
+            __temp1(__temp2(__result));
+            __temp1 = print;
+            __temp2 = foo;
+            __goto = 6;
+            return thenHelper(x, __body, __completer);
+          case 6:
+            // returning from await.
+            __goto = 5;
+            return thenHelper(__temp1(__temp2(__result)), __body, __completer);
+          case 5:
+            // returning from await.
+            __temp1 = print;
+            __temp2 = foo;
+            __temp3 = x;
+            __goto = 7;
+            return thenHelper(y, __body, __completer);
+          case 7:
+            // returning from await.
+            __temp1(__temp2(__temp3, __result, z));
+            // implicit return
+            return thenHelper(null, 0, __completer, null);
+          case 1:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
+
   testTransform("""
-function(x, y) async {
+function(x, y, k) async {
   while (await(foo())) {
     lab: { // labelled statement
       switch(y) {
@@ -838,112 +961,125 @@
     }
   }
 }""", """
-function(x, y) {
-  var __goto = 0, __completer = new Completer(), __returnValue, __temp1;
-  function __helper(__result) {
+function(x, y, k) {
+  var __goto = 0, __completer = new Completer(), __handler = 2, __currentError, __returnValue, __temp1;
+  function __body(__errorCode, __result) {
+    if (__errorCode == 1) {
+      __currentError = __result;
+      __goto = __handler;
+    }
     while (true)
-      switch (__goto) {
-        case 0:
-          // Function start
-        case 2:
-          // while condition
-          __goto = 4;
-          return thenHelper(foo(), __helper, __completer, null);
-        case 4:
-          // returning from await.
-          if (!__result) {
-            // goto after while
+      try {
+        switch (__goto) {
+          case 0:
+            // Function start
+          case 3:
+            // while condition
+            __goto = 5;
+            return thenHelper(foo(), __body, __completer);
+          case 5:
+            // returning from await.
+            if (!__result) {
+              // goto after while
+              __goto = 4;
+              break;
+            }
+          case 7:
+            // continue lab
+          case 8:
+            // switch
+            __temp1 = y;
+            if (__temp1 === 0) {
+              // goto case
+              __goto = 10;
+              break;
+            }
+            if (__temp1 === 0) {
+              // goto case
+              __goto = 11;
+              break;
+            }
+            __goto = 13;
+            return thenHelper(bar(), __body, __completer);
+          case 13:
+            // returning from await.
+            if (__temp1 === __result) {
+              // goto case
+              __goto = 12;
+              break;
+            }
+            if (__temp1 === x) {
+              // goto case
+              __goto = 14;
+              break;
+            }
+            // goto default
+            __goto = 15;
+            break;
+          case 10:
+            // case
+            foo();
+          case 11:
+            // case
+            __temp1 = print;
+            __goto = 16;
+            return thenHelper(foo1(x), __body, __completer);
+          case 16:
+            // returning from await.
+            __temp1(__result);
+            __returnValue = y;
+            // goto return
+            __goto = 1;
+            break;
+          case 12:
+            // case
+            __temp1 = print;
+            __goto = 17;
+            return thenHelper(foobar(x), __body, __completer);
+          case 17:
+            // returning from await.
+            __temp1(__result);
+            __returnValue = y;
+            // goto return
+            __goto = 1;
+            break;
+          case 14:
+            // case
+            if (a) {
+              throw new Error();
+            } else {
+              // goto while condition
+              __goto = 3;
+              break;
+            }
+          case 15:
+            // default
+            // goto break lab
+            __goto = 6;
+            break;
+          case 9:
+            // after switch
+            foo();
+          case 6:
+            // break lab
+            // goto while condition
             __goto = 3;
             break;
-          }
-        case 6:
-          // continue lab
-        case 7:
-          // switch
-          __temp1 = y;
-          if (__temp1 === 0) {
-            // goto case
-            __goto = 9;
-            break;
-          }
-          if (__temp1 === 0) {
-            // goto case
-            __goto = 10;
-            break;
-          }
-          __goto = 12;
-          return thenHelper(bar(), __helper, __completer, null);
-        case 12:
-          // returning from await.
-          if (__temp1 === __result) {
-            // goto case
-            __goto = 11;
-            break;
-          }
-          if (__temp1 === x) {
-            // goto case
-            __goto = 13;
-            break;
-          }
-          // goto default
-          __goto = 14;
-          break;
-        case 9:
-          // case
-          foo();
-        case 10:
-          // case
-          __temp1 = print;
-          __goto = 15;
-          return thenHelper(foo1(x), __helper, __completer, null);
-        case 15:
-          // returning from await.
-          __temp1(__result);
-          __returnValue = y;
-          // goto return
-          __goto = 1;
-          break;
-        case 11:
-          // case
-          __temp1 = print;
-          __goto = 16;
-          return thenHelper(foobar(x), __helper, __completer, null);
-        case 16:
-          // returning from await.
-          __temp1(__result);
-          __returnValue = y;
-          // goto return
-          __goto = 1;
-          break;
-        case 13:
-          // case
-          if (a) {
-            throw new Error();
-          } else {
-            // goto while condition
-            __goto = 2;
-            break;
-          }
-        case 14:
-          // default
-          // goto break lab
-          __goto = 5;
-          break;
-        case 8:
-          // after switch
-          foo();
-        case 5:
-          // break lab
-          // goto while condition
-          __goto = 2;
-          break;
-        case 3:
-          // after while
-        case 1:
-          // return
-          return thenHelper(__returnValue, null, __completer, null);
+          case 4:
+            // after while
+          case 1:
+            // return
+            return thenHelper(__returnValue, 0, __completer, null);
+          case 2:
+            // rethrow
+            return thenHelper(__currentError, 1, __completer);
+        }
+      } catch (__error) {
+        __currentError = __error;
+        __goto = __handler;
       }
+
   }
-  return thenHelper(null, __helper, __completer, null);
+  return thenHelper(null, __body, __completer, null);
 }""");
 }
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index ab820a4..ffa2dab 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -98,6 +98,7 @@
   'assertIsSubtype': 'assertIsSubtype(subtype, supertype, message) {}',
   'assertSubtype': 'assertSubtype(object, isField, checks, asField) {}',
   'assertSubtypeOfRuntimeType': 'assertSubtypeOfRuntimeType(object, type) {}',
+  'asyncHelper': 'asyncHelper(object, asyncBody, completer) {}',
   'boolConversionCheck': 'boolConversionCheck(x) {}',
   'boolTypeCast': 'boolTypeCast(value) {}',
   'boolTypeCheck': 'boolTypeCheck(value) {}',
@@ -209,8 +210,6 @@
   'stringTypeCheck': 'stringTypeCheck(x) {}',
   'subtypeCast': 'subtypeCast(object, isField, checks, asField) {}',
   'subtypeOfRuntimeTypeCast': 'subtypeOfRuntimeTypeCast(object, type) {}',
-  'thenHelper':
-      'thenHelper(object, helperCallback, completer, errorCallback) {}',
   'throwAbstractClassInstantiationError':
       'throwAbstractClassInstantiationError(className) {}',
   'throwCyclicInit': 'throwCyclicInit(staticName) {}',
diff --git a/tests/compiler/dart2js_extra/21166_test.dart b/tests/compiler/dart2js_extra/21166_test.dart
new file mode 100644
index 0000000..bc8f63b
--- /dev/null
+++ b/tests/compiler/dart2js_extra/21166_test.dart
@@ -0,0 +1,25 @@
+// 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.
+
+// Regression test for http://dartbug.com/21166/
+// Fails when compiling with --checked.
+
+var a = [];
+
+void doStuff() {
+  if (a.length) { // This triggers a TypeConversion to bool in checked mode.
+    var element = a[0]; // This triggers a bounds check but a.length will have
+    a.remove(element);  // type [empty].
+  }
+}
+
+main() {
+  a.add(1);
+  a.add(2);
+  try {
+    doStuff(); // This is expected to fail but not crash the compiler.
+  } catch (_) {}
+}
+
+
diff --git a/tests/language/async_return_types_test.dart b/tests/language/async_return_types_test.dart
new file mode 100644
index 0000000..83eb9a8
--- /dev/null
+++ b/tests/language/async_return_types_test.dart
@@ -0,0 +1,55 @@
+// 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:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+Future foo1() async {
+  return 3;
+}
+
+Future<int> foo2() async {
+  return 3;
+}
+
+Future<int> /// wrongTypeParameter: static type warning
+foo3() async {
+  return "String";
+}
+
+// Future<int, String> is treated like Future<dynamic>
+Future<int, String> /// tooManyTypeParameters: static type warning
+foo4() async {
+  return "String";
+}
+
+int /// wrongReturnType: static type warning, dynamic type error
+foo5() async {
+  return 3;
+}
+
+Future<int> foo6() async { 
+  // This is fine, the future is flattened
+  return new Future<int>.value(3);
+}
+
+Future<Future<int>> /// nestedFuture: static type warning
+foo7() async {
+  return new Future<int>.value(3);
+}
+
+test() async {
+  Expect.equals(3, await foo1());
+  Expect.equals(3, await foo2());
+  Expect.equals("String", await foo3());
+  Expect.equals("String", await foo4());
+  Expect.equals(3, await foo5());
+  Expect.equals(3, await await foo6());
+  Expect.equals(3, await await foo7());
+}
+
+main() {
+  asyncTest(test);
+}
\ No newline at end of file
diff --git a/tests/language/async_throw_in_catch_test.dart b/tests/language/async_throw_in_catch_test.dart
new file mode 100644
index 0000000..1cb741e
--- /dev/null
+++ b/tests/language/async_throw_in_catch_test.dart
@@ -0,0 +1,440 @@
+// 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:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+class Tracer {
+  final String expected;
+  final String name;
+  int counter = 0;
+
+  Tracer(this.expected, [this.name]);
+
+  void trace(msg) {
+    if (name != null) {
+      print("Tracing $name: $msg");
+    }
+    Expect.equals(expected[counter], msg);
+    counter++;
+  }
+
+  void done() {
+    Expect.equals(expected.length, counter, "Received too few traces");
+  }
+}
+
+foo1(Tracer tracer) async {
+  try {
+    tracer.trace("a");
+    // This await forces dart2js to rewrite the try into a state machine
+    // instead of relying on the existing structure.
+    await new Future.value(3); /// forceAwait: ok
+    tracer.trace("b");
+    throw "Error";
+  } catch (error) {
+    tracer.trace("c");
+    Expect.equals("Error", error);
+    throw "Error2";
+    tracer.trace("d");
+  } finally {
+    tracer.trace("e");
+  }
+  tracer.trace("f");
+}
+
+foo2(Tracer tracer) async {
+  try {
+    tracer.trace("a");
+    await new Future.value(3); /// forceAwait: continued
+    tracer.trace("b");
+    throw "Error";
+    tracer.trace("c");
+  } catch (error) {
+    tracer.trace("d");
+    Expect.equals("Error", error);
+    await new Future.error("Error2");
+  } finally {
+    tracer.trace("e");
+  }
+  tracer.trace("f");
+}
+
+foo3(Tracer tracer) async {
+  try {
+    tracer.trace("a");
+    await new Future.value(3); /// forceAwait: continued
+    tracer.trace("b");
+    throw "Error";
+    tracer.trace("c");
+  } catch (error) {
+    Expect.equals("Error", error);
+    tracer.trace("d");
+    return;
+  } finally {
+    tracer.trace("e");
+  }
+  tracer.trace("f");
+}
+
+foo4(Tracer tracer) async {
+  try {
+    try {
+      await new Future.value(3); /// forceAwait: continued
+      tracer.trace("a");
+      throw "Error";
+    } catch(error) {
+      tracer.trace("b");
+      Expect.equals("Error", error);
+      throw "Error2";
+    }
+  } catch(error) {
+    Expect.equals("Error2", error);
+    tracer.trace("c");
+  }
+  tracer.trace("d");
+
+}
+
+foo5(Tracer tracer) async {
+  try {
+    tracer.trace("a");
+    try {
+      await new Future.value(3); /// forceAwait: continued
+      tracer.trace("b");
+      throw "Error";
+    } catch(error) {
+      tracer.trace("c");
+      Expect.equals("Error", error);
+      throw "Error2";
+    }
+  } finally {
+    tracer.trace("d");
+  }
+  tracer.trace("e");
+
+}
+
+foo6(Tracer tracer) async {
+  try {
+    try {
+      await new Future.value(3); /// forceAwait: continued
+      tracer.trace("a");
+      throw "Error";
+    } catch(error) {
+      tracer.trace("b");
+      Expect.equals("Error", error);
+      throw "Error2";
+    } finally {
+      tracer.trace("c");
+      throw "Error3";
+    }
+  } catch(error) {
+    tracer.trace("d");
+    Expect.equals("Error3", error);
+  }
+  tracer.trace("e");
+}
+
+foo7(Tracer tracer) async {
+  try {
+    try {
+      await new Future.value(3); /// forceAwait: continued
+      tracer.trace("a");
+      throw "Error";
+    } catch(error) {
+      Expect.equals("Error", error);
+      tracer.trace("b");
+      throw "Error2";
+    } finally {
+      tracer.trace("c");
+      throw "Error3";
+    }
+  } finally {
+    tracer.trace("d");
+  }
+  tracer.trace("e");
+}
+
+foo8(Tracer tracer) async {
+  try {
+    try {
+      await new Future.value(3); /// forceAwait: continued
+      tracer.trace("a");
+      throw "Error";
+    } catch(error) {
+      Expect.equals("Error", error);
+      tracer.trace("b");
+      return;
+    } finally {
+      tracer.trace("c");
+      throw "Error3";
+    }
+  } finally {
+    tracer.trace("d");
+  }
+  tracer.trace("e");
+}
+
+foo9(Tracer tracer) async {
+  try {
+    while(true) {
+      try {
+        await new Future.value(3); /// forceAwait: continued
+        tracer.trace("a");
+        throw "Error";
+      } catch(error) {
+        Expect.equals("Error", error);
+        tracer.trace("b");
+        return;
+      } finally {
+        tracer.trace("c");
+        break;
+      }
+      tracer.trace("d");
+    }
+  } finally {
+    tracer.trace("e");
+  }
+  tracer.trace("f");
+}
+
+foo10(Tracer tracer) async {
+  try {
+    int i = 0;
+    while (true) {
+      try {
+        try {
+          tracer.trace("a");
+          throw "Error";
+        } catch (error) {
+          tracer.trace("b");
+          try {
+            await new Future.value(3);  /// forceAwait: continued
+            throw "Error2";
+          } catch(error) {
+            tracer.trace("c");
+          } finally {
+            tracer.trace("d");
+          }
+          tracer.trace("e");
+          throw "Error3";
+        } finally {
+          tracer.trace("f");
+          // Continue and breaks 'eats' Error3.
+          if (i == 0) continue;
+          if (i == 1) break;
+        }
+      } finally {
+        tracer.trace("g");
+        i++;
+      }
+    }
+  } finally {
+    tracer.trace("h");
+  }
+  tracer.trace("i");
+}
+
+foo11(Tracer tracer) async {
+  try {
+    bool firstTime = true;
+    while(true) {
+      tracer.trace("a");
+      if (firstTime) {
+        try {
+          await new Future.value(3); /// forceAwait: continued
+          tracer.trace("b");
+          throw "Error";
+        } catch(error) {
+          Expect.equals("Error", error);
+          tracer.trace("c");
+          firstTime = false;
+          continue;
+        } finally {
+          tracer.trace("d");
+        }
+      } else {
+        tracer.trace("e");
+        return;
+      }
+    }
+  } finally {
+    tracer.trace("f");
+  }
+  tracer.trace("g");
+}
+
+foo12(Tracer tracer) async {
+  try {
+    bool firstTime = true;
+    while(true) {
+      tracer.trace("a");
+      if (firstTime) {
+        try {
+          await new Future.value(3); /// forceAwait: continued
+          tracer.trace("b");
+          throw "Error";
+        } catch(error) {
+          Expect.equals("Error", error);
+          tracer.trace("c");
+          firstTime = false;
+          continue;
+        } finally {
+          tracer.trace("d");
+          break;
+        }
+      } else {
+        tracer.trace("e");
+        return;
+      }
+    }
+  } finally {
+    tracer.trace("f");
+  }
+  tracer.trace("g");
+}
+
+foo13(Tracer tracer) async {
+  try {
+    try {
+      tracer.trace("a");
+      return;
+    } catch (error) {
+      tracer.trace("b");
+    } finally {
+      tracer.trace("c");
+      try {
+        try {
+          await new Future.value(3);  /// forceAwait: continued
+          tracer.trace("d");
+          throw "Error";
+        } finally {
+          tracer.trace("e");
+        }
+      } finally {
+        tracer.trace("f");
+      }
+    }
+  } finally {
+    tracer.trace("g");
+  }
+  tracer.trace("h");
+}
+
+foo14(Tracer tracer) async {
+  try {
+    try {
+      tracer.trace("a");
+      throw "Error";
+    } catch (error) {
+      tracer.trace("b");
+      try {
+        await new Future.value(3);  /// forceAwait: continued
+        throw "Error2";
+      } catch(error) {
+        tracer.trace("c");
+      } finally {
+        tracer.trace("d");
+      }
+      tracer.trace("e");
+      throw "Error3";
+    } finally {
+      tracer.trace("f");
+    }
+  } finally {
+    tracer.trace("g");
+  }
+  tracer.trace("h");
+}
+
+foo15(Tracer tracer) async {
+  try {
+    try {
+      tracer.trace("a");
+      throw "Error";
+    } catch (error) {
+      tracer.trace("b");
+      try {
+        await new Future.value(3);  /// forceAwait: continued
+        throw "Error2";
+      } catch(error) {
+        tracer.trace("c");
+      } finally {
+        tracer.trace("d");
+      }
+      tracer.trace("e");
+      throw "Error3";
+    } finally {
+      tracer.trace("f");
+      return;
+    }
+  } finally {
+    tracer.trace("g");
+  }
+  tracer.trace("h");
+}
+
+foo16(Tracer tracer) async {
+  try {
+    try {
+      tracer.trace("a");
+      throw "Error";
+    } catch (error) {
+      tracer.trace("b");
+      try {
+        await new Future.value(3);  /// forceAwait: continued
+        throw "Error2";
+      } catch(error) {
+        tracer.trace("c");
+      } finally {
+        tracer.trace("d");
+        return;
+      }
+      tracer.trace("e");
+      throw "Error3";
+    } finally {
+      tracer.trace("f");
+    }
+  } finally {
+    tracer.trace("g");
+  }
+  tracer.trace("h");
+}
+
+runTest(expectedTrace, fun, [expectedError]) async {
+  Tracer tracer = new Tracer(expectedTrace);
+  try {
+    await fun(tracer);
+  } catch (error) {
+    Expect.equals(expectedError, error);
+    tracer.trace("X");
+  }
+  tracer.done();
+}
+
+test() async {
+  await runTest("abceX", foo1, "Error2");
+  await runTest("abdeX", foo2, "Error2");
+  await runTest("abde", foo3);
+  await runTest("abcd", foo4);
+  await runTest("abcdX", foo5, "Error2");
+  await runTest("abcde", foo6);
+  await runTest("abcdX", foo7, "Error3");
+  await runTest("abcdX", foo8, "Error3");
+  await runTest("abcef", foo9);
+  await runTest("abcdefgabcdefghi", foo10);
+  await runTest("abcdaef", foo11);
+  await runTest("abcdfg", foo12);
+  await runTest("acdefgX", foo13, "Error");
+  await runTest("abcdefgX", foo14, "Error3");
+  await runTest("abcdefgX", foo14, "Error3");
+  await runTest("abcdefg", foo15);
+  await runTest("abcdfg", foo16);
+}
+
+void main() {
+  asyncTest(test);
+}
\ No newline at end of file
diff --git a/tests/language/asyncstar_throw_in_catch_test.dart b/tests/language/asyncstar_throw_in_catch_test.dart
new file mode 100644
index 0000000..a6f6a33
--- /dev/null
+++ b/tests/language/asyncstar_throw_in_catch_test.dart
@@ -0,0 +1,65 @@
+// 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:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+class Tracer {
+  final String expected;
+  final String name;
+  int counter = 0;
+
+  Tracer(this.expected, [this.name]);
+
+  void trace(msg) {
+    if (name != null) {
+      print("Tracing $name: $msg");
+    }
+    Expect.equals(expected[counter], msg);
+    counter++;
+  }
+
+  void done() {
+    Expect.equals(expected.length, counter, "Received too few traces");
+  }
+}
+
+foo1(Tracer tracer) async* {
+  try {
+    tracer.trace("a");
+    await new Future.value(3);
+    tracer.trace("b");
+    throw "Error";
+  } catch (e) {
+    tracer.trace("c");
+    yield 1;
+    tracer.trace("d");
+    yield 2;
+    tracer.trace("e");
+    await new Future.error("Error2");
+  } finally {
+    tracer.trace("f");
+  }
+  tracer.trace("g");
+}
+
+test() async {
+  Tracer tracer;
+
+  Completer foo1Done = new Completer();
+  tracer = new Tracer("abcdf");
+  var subscription;
+  subscription = foo1(tracer).listen((event) async {
+    await subscription.cancel();
+    tracer.done();
+    foo1Done.complete(null);
+  });
+  await foo1Done.future;
+}
+
+
+void main() {
+  asyncTest(test);
+}
\ No newline at end of file
diff --git a/tests/language/language.status b/tests/language/language.status
index 733ba43..71c570c 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -55,7 +55,9 @@
 async_await_syntax_test/d10a: CompileTimeError # Issue 21404
 
 [ $compiler == none || ($compiler == dart2dart && $builder_tag != new_backend) ]
+async_throw_in_catch_test: Crash # Issue 22445, 22446
 compile_time_constant_c_test/01: Fail # Issue 21000
+asyncstar_throw_in_catch_test: CompileTimeError # Issue 21404
 async_await_syntax_test/a03a: CompileTimeError # Issue 21404
 async_await_syntax_test/a03b: CompileTimeError # Issue 21404
 async_await_syntax_test/a11d: CompileTimeError # Issue 21404
@@ -66,6 +68,8 @@
 sync_generator3_test/test2: Fail # Issue 22300
 
 [ $compiler == none && ($runtime == drt || $runtime == dartium|| $runtime == ContentShellOnAndroid) ]
+async_throw_in_catch_test: Timeout # Issue 22445, 22446
+asyncstar_throw_in_catch_test: RuntimeError # Issue 21404
 async_await_syntax_test/a03a: RuntimeError # Issue 21404
 async_await_syntax_test/a03b: RuntimeError # Issue 21404
 async_await_syntax_test/a09a: RuntimeError # Issue 21404
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 357491a..67fe963 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -3,9 +3,13 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dartanalyzer ]
-
+async_return_types_test/wrongTypeParameter: MissingStaticWarning # Issue 22410
+async_return_types_test/wrongReturnType: MissingStaticWarning # Issue 22410
+async_return_types_test/nestedFuture: MissingStaticWarning # Issue 22410
 await_backwards_compatibility_test/none: CompileTimeError # Issue 22052
 await_test: CompileTimeError # Issue 22052
+asyncstar_yield_test: StaticWarning # Issue 22411
+sync_generator1_test/01: MissingStaticWarning # Issue 22412
 
 sync_generator2_test/01: MissingCompileTimeError # Issue 22252
 sync_generator2_test/02: MissingCompileTimeError # Issue 22252
@@ -26,6 +30,7 @@
 async_await_syntax_test/a10a: MissingStaticWarning
 async_await_syntax_test/b10a: MissingStaticWarning
 async_await_syntax_test/c10a: MissingStaticWarning
+async_await_syntax_test/d08b: MissingStaticWarning # Issue 22412
 async_await_syntax_test/d10a: MissingStaticWarning
 
 # Runtime negative test. No static errors or warnings.
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 40de933..8048046 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -2,10 +2,6 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-[ $compiler == dart2js && $checked ]
-await_future_test: RuntimeError # Issue 22332
-async_test/none: RuntimeError # Issue 22332
-
 [ $compiler == dart2js ]
 syncstar_yield_test/copyParameters: RuntimeError # Issue 22322
 sync_generator2_test/07: MissingCompileTimeError # Issue 22324
@@ -194,6 +190,7 @@
 label_test: Skip
 
 [ $compiler == dart2dart && $builder_tag == new_backend ]
+asyncstar_throw_in_catch_test: CompileTimeError # Issue 21404
 await_for_test: RuntimeError # Issue 22051
 await_regression_test: RuntimeError # Issue 22051
 async_await_syntax_test/a06a: RuntimeError # Issue 22051
diff --git a/tests/language/sync_generator3_test.dart b/tests/language/sync_generator3_test.dart
index d84275e..a993a27 100644
--- a/tests/language/sync_generator3_test.dart
+++ b/tests/language/sync_generator3_test.dart
@@ -34,14 +34,12 @@
 }
 
 test2() {
-  var s;
-  try {
-    s = g().toString();
-  } catch (e) {
-    Expect.equals("pow!", e);
-    Expect.equals("(a, b)", s);
-    print(s);
-  }
+  Iterator i = g().iterator;
+  Expect.isTrue(i.moveNext());
+  Expect.equals("a", i.current);
+  Expect.isTrue(i.moveNext());
+  Expect.equals("b", i.current);
+  Expect.throws(() => i.moveNext(), (error) => error == "pow!");
 }
 
 main() {
diff --git a/tests/standalone/io/http_bind_test.dart b/tests/standalone/io/http_bind_test.dart
new file mode 100644
index 0000000..a399b19
--- /dev/null
+++ b/tests/standalone/io/http_bind_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:convert';
+
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+
+testBindShared(String host, bool v6Only) async {
+  asyncStart();
+
+  // Sent a single request using a new HttpClient to ensure a new TCP
+  // connnection is used.
+  Future singleRequest(host, port, statusCode) async {
+    var client = new HttpClient();
+    var request = await client.open('GET', host, port, '/');
+    var response = await request.close();
+    await response.drain();
+    Expect.equals(statusCode, response.statusCode);
+    client.close(force: true);
+  }
+
+  Completer server1Request = new Completer();
+  Completer server2Request = new Completer();
+
+  var server1 = await HttpServer.bind(host, 0, v6Only: v6Only, shared: true);
+  var port = server1.port;
+  Expect.isTrue(port > 0);
+
+  var server2 = await HttpServer.bind(host, port, v6Only: v6Only, shared: true);
+  Expect.equals(server1.address.address, server2.address.address);
+  Expect.equals(port, server2.port);
+
+  server1.listen((request) {
+    server1Request.complete();
+    request.response.statusCode = 501;
+    request.response.close();
+  });
+
+  await singleRequest(host, port, 501);
+  await server1.close();
+
+  server2.listen((request) {
+    server2Request.complete();
+    request.response.statusCode = 502;
+    request.response.close();
+  });
+
+  await singleRequest(host, port, 502);
+  await server2.close();
+
+  await server1Request.future;
+  await server2Request.future;
+
+  asyncEnd();
+}
+
+void main() {
+  for (var host in ['127.0.0.1', '::1']) {
+    testBindShared(host, false);
+    testBindShared(host, true);
+  }
+}
diff --git a/tools/VERSION b/tools/VERSION
index 9130654..d7305aa 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 9
 PATCH 0
 PRERELEASE 8
-PRERELEASE_PATCH 2
+PRERELEASE_PATCH 3