Version 2.12.0-136.0.dev

Merge commit '425780f410f668608bb3a675f9d52811bde973ad' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0d0877..685ce1b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,14 @@
 * `LinkedList` made it explicit that elements are compared by identity,
   and updated `contains` to take advantage of this.
 
+#### `dart:html`
+
+* `EventStreamSubscription.cancel` has been updated to retain its synchronous
+  timing when running in both sound and unsound null safety modes. See issue
+  [#44157][] for more details.
+
+[#44157]: https://github.com/dart-lang/sdk/issues/44157
+
 ### Dart VM
 
 *   **Breaking Change** [#42312][]: `Dart_WeakPersistentHandle`s will no longer
@@ -117,9 +125,23 @@
 * New command `dart pub add` that adds  new dependencies to your `pubspec.yaml`.
 
   And a corresponding `dart pub remove` that removes dependencies.
+* New option `dart pub upgrade --major-versions` will update constraints in
+  your `pubspec.yaml` to match the the _resolvable_ column reported in
+  `dart pub outdated`. This allows users to easily upgrade to latest version for
+  all dependencies where this is possible, even if such upgrade requires an
+  update to the version constraint in `pubspec.yaml`.
+
+  It is also possible to only upgrade the major version for a subset of your
+  dependencies using `dart pub upgrade --major-versions <dependencies...>`.
+* New option `dart pub upgrade --null-safety` will attempt to update constraints
+  in your `pubspec.yaml`, such that only null-safety migrated versions of
+  dependencies are allowed.
 * New option `dart pub outdated --mode=null-safety` that will analyze your
   dependencies for null-safety.
 * `dart pub publish` will now check your pubspec keys for likely typos.
+* `dart pub upgrade package_foo` will fetch dependencies, but ignore the
+  `pubspec.lock` for `package_foo`, allowing users to only upgrade a subset of
+  dependencies.
 * New command `dart pub login` that logs in to pub.dev.
 * The `--server` option to `dart pub publish` and `dart pub uploader` have been
   deprecated. Use `publish_to` in your `pubspec.yaml` or set the
diff --git a/DEPS b/DEPS
index 113420e..5eb902f 100644
--- a/DEPS
+++ b/DEPS
@@ -108,7 +108,7 @@
   "glob_rev": "7c0ef8d4fa086f6b185c4dd724b700e7d7ad8f79",
   "html_rev": "22f17e97fedeacaa1e945cf84d8016284eed33a6",
   "http_io_rev": "2fa188caf7937e313026557713f7feffedd4978b",
-  "http_multi_server_rev" : "f1d1c9c024a293ab0a0e16f8b7632e87c708b448",
+  "http_multi_server_rev" : "e8c8be7f15b4fb50757ff5bf29766721fbe24fe4",
   "http_parser_rev": "5dd4d16693242049dfb43b5efa429fedbf932e98",
   "http_retry_tag": "0.1.1",
   "http_rev": "1617b728fc48f64fb0ed7dc16078c03adcc64179",
@@ -133,7 +133,7 @@
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "protobuf_rev": "0d03fd588df69e9863e2a2efc0059dee8f18d5b2",
-  "pub_rev": "228e69e53862879c283c42b98086aa7536012a66",
+  "pub_rev": "8ea96121dbb3f762f63e641d49141927dc30aac1",
   "pub_semver_rev": "10569a1e867e909cf5db201f73118020453e5db8",
   "resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
   "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
@@ -141,7 +141,7 @@
   "shelf_static_rev": "779a6e99b320ce9ed4ff6b88bd0cdc40ea5c62c4",
   "shelf_packages_handler_tag": "2.0.0",
   "shelf_proxy_tag": "0.1.0+7",
-  "shelf_rev": "5a77d25861db91db4343b19dfe213b8992e0a837",
+  "shelf_rev": "fa5afaa38bd51dedeeaa25b7bfd8822cabbcc57f",
   "shelf_web_socket_rev": "8050a55b16faa5052a3e5d7dcdc170c59b6644f2",
   "source_map_stack_trace_rev": "1c3026f69d9771acf2f8c176a1ab750463309cce",
   "source_maps-0.9.4_rev": "38524",
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index c37c64c..62cf759 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -31,6 +31,7 @@
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/src/util/glob.dart';
 import 'package:analyzer/src/util/yaml.dart';
+import 'package:analyzer/src/workspace/bazel.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
 import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
 import 'package:path/path.dart' as pathos;
@@ -393,6 +394,11 @@
   final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions =
       <Folder, StreamSubscription<WatchEvent>>{};
 
+  /// For each root directory stores subscriptions and watchers that we
+  /// established to detect changes to Bazel generated files.
+  final Map<Folder, _BazelWorkspaceSubscription> bazelSubscriptions =
+      <Folder, _BazelWorkspaceSubscription>{};
+
   ContextManagerImpl(
     this.resourceProvider,
     this.sdkManager,
@@ -1016,6 +1022,7 @@
       contextRoot.optionsFilePath = optionsFile.path;
     }
     info.analysisDriver = callbacks.addAnalysisDriver(folder, contextRoot);
+    _watchBazelFilesIfNeeded(folder, info.analysisDriver);
     if (optionsFile != null) {
       _analyzeAnalysisOptionsFile(info.analysisDriver, optionsFile.path);
     }
@@ -1116,6 +1123,7 @@
   /// Clean up and destroy the context associated with the given folder.
   void _destroyContext(ContextInfo info) {
     changeSubscriptions.remove(info.folder)?.cancel();
+    bazelSubscriptions.remove(info.folder)?.cancel();
     callbacks.removeContext(info.folder, _computeFlushedFiles(info));
     var wasRemoved = info.parent.children.remove(info);
     assert(wasRemoved);
@@ -1220,6 +1228,47 @@
     return rootInfo;
   }
 
+  /// Establishes watch(es) for the Bazel generated files provided in
+  /// [notification].
+  ///
+  /// Whenever the files change, we trigger re-analysis. This allows us to react
+  /// to creation/modification of files that were generated by Bazel.
+  void _handleBazelFileNotification(
+      Folder folder, BazelFileNotification notification) {
+    var fileSubscriptions = bazelSubscriptions[folder].fileSubscriptions;
+    if (fileSubscriptions.containsKey(notification.requested)) {
+      // We have already established a Watcher for this particular path.
+      return;
+    }
+    var watcher = notification.watcher(
+        pollingDelayShort: Duration(seconds: 10),
+        pollingDelayLong: Duration(seconds: 30));
+    var subscription = watcher.events.listen(_handleBazelWatchEvent);
+    fileSubscriptions[notification.requested] =
+        _BazelFilesSubscription(watcher, subscription);
+    watcher.start();
+  }
+
+  /// Notifies the drivers that a generated Bazel file has changed.
+  void _handleBazelWatchEvent(WatchEvent event) {
+    if (event.type == ChangeType.ADD) {
+      for (var driver in driverMap.values) {
+        driver.addFile(event.path);
+        // Since the file has been created after we've searched for it, the
+        // URI resolution is likely wrong, so we need to reset it.
+        driver.resetUriResolution();
+      }
+    } else if (event.type == ChangeType.MODIFY) {
+      for (var driver in driverMap.values) {
+        driver.changeFile(event.path);
+      }
+    } else if (event.type == ChangeType.REMOVE) {
+      for (var driver in driverMap.values) {
+        driver.removeFile(event.path);
+      }
+    }
+  }
+
   void _handleWatchEvent(WatchEvent event) {
     callbacks.broadcastWatchEvent(event);
     _handleWatchEventImpl(event);
@@ -1504,6 +1553,22 @@
     driver.configure(sourceFactory: sourceFactory);
   }
 
+  /// Listens to files generated by Bazel that were found or searched for.
+  ///
+  /// This is handled specially because the files are outside the package
+  /// folder, but we still want to watch for changes to them.
+  ///
+  /// Does nothing if the [driver] is not in a Bazel workspace.
+  void _watchBazelFilesIfNeeded(Folder folder, AnalysisDriver analysisDriver) {
+    var workspace = analysisDriver.analysisContext.workspace;
+    if (workspace is BazelWorkspace &&
+        !bazelSubscriptions.containsKey(folder)) {
+      var subscription = workspace.bazelCandidateFiles.listen(
+          (notification) => _handleBazelFileNotification(folder, notification));
+      bazelSubscriptions[folder] = _BazelWorkspaceSubscription(subscription);
+    }
+  }
+
   /// Create and return a source representing the given [file] within the given
   /// [driver].
   static Source createSourceInContext(AnalysisDriver driver, File file) {
@@ -1622,3 +1687,36 @@
     return _embedderLocator;
   }
 }
+
+/// A watcher with subscription used to detect changes to some file.
+class _BazelFilesSubscription {
+  final BazelFileWatcher watcher;
+  final StreamSubscription<WatchEvent> subscription;
+
+  _BazelFilesSubscription(this.watcher, this.subscription);
+
+  void cancel() {
+    subscription.cancel();
+    watcher.stop();
+  }
+}
+
+/// A subscription to notifications from a Bazel workspace.
+class _BazelWorkspaceSubscription {
+  final StreamSubscription<BazelFileNotification> workspaceSubscription;
+
+  /// For each absolute path that we searched for, provides the subscriptions
+  /// that we established to watch for changes.
+  ///
+  /// Note that the absolute path used when searching for a file is not
+  /// necessarily the actual path of the file (see [BazelWorkspace.findFile] for
+  /// details on how the files are searched).
+  final fileSubscriptions = <String, _BazelFilesSubscription>{};
+
+  _BazelWorkspaceSubscription(this.workspaceSubscription);
+
+  void cancel() {
+    workspaceSubscription.cancel();
+    fileSubscriptions.values.forEach((sub) => sub.cancel());
+  }
+}
diff --git a/pkg/analysis_server/test/analysis/bazel_changes_test.dart b/pkg/analysis_server/test/analysis/bazel_changes_test.dart
new file mode 100644
index 0000000..168f461
--- /dev/null
+++ b/pkg/analysis_server/test/analysis/bazel_changes_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2020, 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:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_constants.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../analysis_abstract.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(BazelChangesTest);
+  });
+}
+
+@reflectiveTest
+class BazelChangesTest extends AbstractAnalysisTest {
+  Map<String, List<AnalysisError>> filesErrors = {};
+  Completer<void> processedNotification;
+
+  @override
+  void processNotification(Notification notification) {
+    if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) {
+      var decoded = AnalysisErrorsParams.fromNotification(notification);
+      filesErrors[decoded.file] = decoded.errors;
+      processedNotification?.complete();
+    }
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+
+    projectPath = convertPath('/workspaceRoot/third_party/dart/project');
+    testFile =
+        convertPath('/workspaceRoot/third_party/dart/project/lib/test.dart');
+    newFile('/workspaceRoot/WORKSPACE');
+    newFolder('/workspaceRoot/bazel-lib/project');
+    newFolder('/workspaceRoot/bazel-genfiles/project');
+  }
+
+  @override
+  void tearDown() {
+    // Make sure to destroy all the contexts and cancel all subscriptions to
+    // file watchers.
+    server.contextManager.setRoots([], []);
+
+    super.tearDown();
+  }
+
+  Future<void> test_findingFileInGenfiles() async {
+    processedNotification = Completer();
+
+    newFile(testFile, content: r'''
+import 'generated.dart';
+void main() { fun(); }
+''');
+    createProject();
+
+    // We should have some errors since the `generated.dart` is not there yet.
+    await processedNotification.future;
+    expect(filesErrors[testFile], isNotEmpty);
+
+    // Clear errors, so that we'll notice new results.
+    filesErrors.clear();
+    processedNotification = Completer();
+
+    // Simulate the creation of a generated file.
+    newFile(
+        '/workspaceRoot/bazel-genfiles/'
+        'third_party/dart/project/lib/generated.dart',
+        content: 'fun() {}');
+
+    // No errors.
+    await processedNotification.future;
+    expect(filesErrors[testFile], isEmpty);
+  }
+}
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
index 1187065..3329d7f 100644
--- a/pkg/analysis_server/test/analysis/test_all.dart
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -4,6 +4,7 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'bazel_changes_test.dart' as bazel_changes;
 import 'get_errors_test.dart' as get_errors;
 import 'get_hover_test.dart' as get_hover;
 import 'get_navigation_test.dart' as get_navigation;
@@ -26,6 +27,7 @@
 
 void main() {
   defineReflectiveSuite(() {
+    bazel_changes.main();
     get_errors.main();
     get_hover.main();
     get_navigation.main();
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 7a43df7..c91e372 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -114,7 +114,10 @@
     if (builderOptions.librarySummaryPaths != null) {
       summaryData = SummaryDataStore(builderOptions.librarySummaryPaths);
     }
-    final sf = createSourceFactory(path, summaryData: summaryData);
+    Workspace workspace =
+        ContextBuilder.createWorkspace(resourceProvider, path, this);
+    final sf =
+        createSourceFactoryFromWorkspace(workspace, summaryData: summaryData);
 
     AnalysisDriver driver = AnalysisDriver(
       analysisDriverScheduler,
@@ -143,6 +146,7 @@
         resourceProvider,
         apiContextRoots.first,
         driver,
+        workspace: workspace,
       ),
     );
 
@@ -209,6 +213,15 @@
     return workspace.createSourceFactory(sdk, summaryData);
   }
 
+  SourceFactory createSourceFactoryFromWorkspace(Workspace workspace,
+      {SummaryDataStore summaryData}) {
+    DartSdk sdk = findSdk(workspace);
+    if (summaryData != null && sdk is SummaryBasedDartSdk) {
+      summaryData.addBundle(null, sdk.bundle);
+    }
+    return workspace.createSourceFactory(sdk, summaryData);
+  }
+
   /// Add any [declaredVariables] to the list of declared variables used by the
   /// given analysis [driver].
   void declareVariablesInDriver(AnalysisDriver driver) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart b/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
index d02bc2c..0b09d2e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
@@ -29,7 +29,9 @@
   /// to access the file system and that is based on the given analysis
   /// [driver].
   DriverBasedAnalysisContext(
-      this.resourceProvider, this.contextRoot, this.driver) {
+      this.resourceProvider, this.contextRoot, this.driver,
+      {Workspace workspace})
+      : _workspace = workspace {
     driver.analysisContext = this;
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 1f98644..5a9f210 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4357,10 +4357,15 @@
     List<DartType> typeArguments,
     NullabilitySuffix nullabilitySuffix,
   }) {
-    return super.instantiate(
+    var type = super.instantiate(
       typeArguments: typeArguments,
       nullabilitySuffix: nullabilitySuffix,
-    ) as FunctionType;
+    );
+    if (type is FunctionType) {
+      return type;
+    } else {
+      return _errorFunctionType(nullabilitySuffix);
+    }
   }
 }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 32e61ba..3413ad8 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -132,6 +132,13 @@
           name,
           _resolver.typeProvider.typeType.element,
         );
+      } else if (element is TypeAliasElement) {
+        var aliasedType = element.aliasedType;
+        if (aliasedType is InterfaceType) {
+          _resolveReceiverTypeLiteral(
+              node, aliasedType.element, nameNode, name);
+          return;
+        }
       }
     }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index a271757e..a649b31 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -298,15 +298,24 @@
     if (target is Identifier) {
       var targetElement = target.staticElement;
       if (targetElement is ClassElement) {
-        if (isCascaded) {
-          targetElement = _resolver.typeProvider.typeType.element;
-        }
         return _resolveTargetClassElement(
           typeReference: targetElement,
+          isCascaded: isCascaded,
           propertyName: propertyName,
           hasRead: hasRead,
           hasWrite: hasWrite,
         );
+      } else if (targetElement is TypeAliasElement) {
+        var aliasedType = targetElement.aliasedType;
+        if (aliasedType is InterfaceType) {
+          return _resolveTargetClassElement(
+            typeReference: aliasedType.element,
+            isCascaded: isCascaded,
+            propertyName: propertyName,
+            hasRead: hasRead,
+            hasWrite: hasWrite,
+          );
+        }
       }
     }
 
@@ -382,10 +391,15 @@
 
   PropertyElementResolverResult _resolveTargetClassElement({
     @required ClassElement typeReference,
+    @required bool isCascaded,
     @required SimpleIdentifier propertyName,
     @required bool hasRead,
     @required bool hasWrite,
   }) {
+    if (isCascaded) {
+      typeReference = _resolver.typeProvider.typeType.element;
+    }
+
     ExecutableElement readElement;
     if (hasRead) {
       readElement = typeReference.getGetter(propertyName.name);
diff --git a/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
index d3b354b..785ea9f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
@@ -246,9 +246,8 @@
       }
       return;
     } else if (element is TypeAliasElement) {
-      if (node.inDeclarationContext() || node.parent is TypeName) {
-        // no type
-      } else {
+      if (_isExpressionIdentifier(node) ||
+          element.aliasedType is! InterfaceType) {
         node.staticType = _typeProvider.typeType;
       }
       return;
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 5864421..54fb25c 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -723,9 +723,14 @@
   /// returned.
   static ClassElement getTypeReference(Expression expression) {
     if (expression is Identifier) {
-      Element staticElement = expression.staticElement;
-      if (staticElement is ClassElement) {
-        return staticElement;
+      var element = expression.staticElement;
+      if (element is ClassElement) {
+        return element;
+      } else if (element is TypeAliasElement) {
+        var aliasedType = element.aliasedType;
+        if (aliasedType is InterfaceType) {
+          return aliasedType.element;
+        }
       }
     }
     return null;
diff --git a/pkg/analyzer/lib/src/summary2/type_alias.dart b/pkg/analyzer/lib/src/summary2/type_alias.dart
index f69f097..303646c 100644
--- a/pkg/analyzer/lib/src/summary2/type_alias.dart
+++ b/pkg/analyzer/lib/src/summary2/type_alias.dart
@@ -43,12 +43,8 @@
   }
 
   void genericTypeAlias(GenericTypeAlias node) {
-    var functionType = node.functionType;
-    if (functionType != null) {
-      _typeParameterList(functionType.typeParameters);
-      _formalParameterList(functionType.parameters);
-      _visit(functionType.returnType);
-    }
+    _typeParameterList(node.typeParameters);
+    _visit(node.type);
   }
 
   void _argumentList(TypeArgumentList node) {
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index da3cafa..d32be7a 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:collection';
 import 'dart:core';
 
@@ -14,8 +15,43 @@
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/util/uri.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as path;
 import 'package:pub_semver/pub_semver.dart';
+import 'package:watcher/watcher.dart';
+
+/// Notification that we issue in [BazelWorkspace.findFile] when searching for
+/// generated files.
+///
+/// This allows clients to watch for changes to the generated files.
+class BazelFileNotification {
+  /// Candidate paths that we searched.
+  ///
+  /// If it's a singleton, then the file was found/resolved.
+  final List<String> candidates;
+
+  /// Absolute path that we tried searching for.
+  ///
+  /// This is not necessarily the path of the actual file that will be used. See
+  /// [BazelWorkspace.findFile] for details.
+  final String requested;
+
+  final ResourceProvider _provider;
+
+  BazelFileNotification(this.requested, this.candidates, this._provider);
+
+  BazelFileWatcher watcher(
+          {@required Duration pollingDelayShort,
+          @required Duration pollingDelayLong,
+          Timer Function(Duration, void Function(Timer)) timerFactory =
+              _defaultTimerFactory}) =>
+      BazelFileWatcher(candidates, _provider, pollingDelayShort,
+          pollingDelayLong, timerFactory);
+
+  static Timer _defaultTimerFactory(
+          Duration duration, void Function(Timer) callback) =>
+      Timer.periodic(duration, callback);
+}
 
 /// Instances of the class `BazelFileUriResolver` resolve `file` URI's by first
 /// resolving file uri's in the expected way, and then by looking in the
@@ -41,6 +77,140 @@
   }
 }
 
+/// Watches a list of files that should be generated by Bazel.
+///
+/// If we didn't find the file initially, we'll have more that one potential
+/// path. We'll poll them with a shorter delay waiting for at least one
+/// of the paths to become valid (we assume that users will generate the rather
+/// sooner than later since they will likely see errors due to unresolved
+/// files). Once a file appears, we switch to a different mode, where we only
+/// watch that particular file and poll it less frequently. If the file is
+/// deleted we go back to the initial mode of eager polling for all paths.
+class BazelFileWatcher {
+  /// The paths of files that we watch for.
+  ///
+  /// If it's a singleton, then the file was found/resolved by the
+  /// [BazelWorkspace].
+  final List<String> _candidates;
+
+  final _eventsController = StreamController<WatchEvent>.broadcast();
+
+  /// The time of last modification of the file under [_validPath].
+  int _lastModified;
+
+  /// How often do we poll a file that we have found.
+  final Duration _pollingDelayLong;
+
+  /// How often do we poll when none of potential files exist.
+  final Duration _pollingDelayShort;
+
+  final ResourceProvider _provider;
+
+  /// One of the [_candidates] that is valid, i.e., we found a file with that
+  /// path.
+  String _validPath;
+
+  Timer _timer;
+
+  /// Used to contruct a [Timer] for polling.
+  final Timer Function(Duration, void Function(Timer)) _timerFactory;
+
+  BazelFileWatcher(this._candidates, this._provider, this._pollingDelayShort,
+      this._pollingDelayLong, this._timerFactory);
+
+  Stream<WatchEvent> get events => _eventsController.stream;
+
+  /// Starts watching the files.
+  ///
+  /// To avoid missing events, the clients should first start listening on
+  /// [events] and then call [start].
+  void start() {
+    assert(_timer == null);
+    var info = _pollAll();
+    if (info != null) {
+      _validPath = info.path;
+      _lastModified = info.modified;
+      _setPollingDelayToLong();
+    } else {
+      _setPollingDelayToShort();
+    }
+  }
+
+  void stop() {
+    _timer.cancel();
+    _eventsController.close();
+  }
+
+  void _poll() {
+    if (_eventsController.isClosed) return;
+
+    int modified;
+    if (_validPath == null) {
+      var info = _pollAll();
+      if (info != null) {
+        _validPath = info.path;
+        modified = info.modified;
+      }
+    } else {
+      modified = _pollOne(_validPath);
+    }
+
+    // If there is no file, then we have nothing to do.
+    if (_validPath == null) return;
+
+    if (modified == null && _lastModified != null) {
+      // The file is no longer there, so let's issue a REMOVE event, unset
+      // `_validPath` and set the timer to poll more frequently.
+      _eventsController.add(WatchEvent(ChangeType.REMOVE, _validPath));
+      _validPath = null;
+      _setPollingDelayToShort();
+    } else if (modified != null && _lastModified == null) {
+      _eventsController.add(WatchEvent(ChangeType.ADD, _validPath));
+      _setPollingDelayToLong();
+    } else if (_lastModified != null && modified != _lastModified) {
+      _eventsController.add(WatchEvent(ChangeType.MODIFY, _validPath));
+    }
+    _lastModified = modified;
+  }
+
+  /// Tries polling all the possible paths.
+  ///
+  /// Will set [_validPath] and return its modified time if a file is found.
+  /// Returns [null] if nothing is found.
+  FileInfo _pollAll() {
+    assert(_validPath == null);
+    for (var path in _candidates) {
+      var modified = _pollOne(path);
+      if (modified != null) {
+        return FileInfo(path, modified);
+      }
+    }
+    return null;
+  }
+
+  /// Returns the modified time of the path or `null` if the file does not
+  /// exist.
+  int _pollOne(String path) {
+    try {
+      var file = _provider.getFile(path);
+      return file.modificationStamp;
+    } on FileSystemException catch (_) {
+      // File doesn't exist, so return null.
+      return null;
+    }
+  }
+
+  void _setPollingDelayToLong() {
+    _timer?.cancel();
+    _timer = _timerFactory(_pollingDelayLong, (_) => _poll());
+  }
+
+  void _setPollingDelayToShort() {
+    _timer?.cancel();
+    _timer = _timerFactory(_pollingDelayShort, (_) => _poll());
+  }
+}
+
 /// The [UriResolver] that can resolve `package` URIs in [BazelWorkspace].
 class BazelPackageUriResolver extends UriResolver {
   final BazelWorkspace _workspace;
@@ -189,9 +359,17 @@
   /// The absolute path to the `bazel-genfiles` folder.
   final String genfiles;
 
+  final _bazelCandidateFiles =
+      StreamController<BazelFileNotification>.broadcast();
+
   BazelWorkspace._(
       this.provider, this.root, this.readonly, this.binPaths, this.genfiles);
 
+  /// Stream of files that we tried to find along with their potential or actual
+  /// paths.
+  Stream<BazelFileNotification> get bazelCandidateFiles =>
+      _bazelCandidateFiles.stream;
+
   @override
   bool get isBazel => true;
 
@@ -224,17 +402,16 @@
       if (relative == '.') {
         return null;
       }
-      // genfiles
-      if (genfiles != null) {
-        File file = provider.getFile(context.join(genfiles, relative));
+      // First check genfiles and bin directories
+      var generatedCandidates = <String>[
+        if (genfiles != null) genfiles,
+        ...?binPaths
+      ].map((prefix) => context.join(prefix, relative));
+      for (var path in generatedCandidates) {
+        File file = provider.getFile(path);
         if (file.exists) {
-          return file;
-        }
-      }
-      // bin
-      for (String bin in binPaths) {
-        File file = provider.getFile(context.join(bin, relative));
-        if (file.exists) {
+          _bazelCandidateFiles.add(BazelFileNotification(
+              relative, generatedCandidates.toList(), provider));
           return file;
         }
       }
@@ -250,6 +427,10 @@
           return file;
         }
       }
+      // If we couldn't find the file, assume that it has not yet been
+      // generated, so send an event with all the paths that we tried.
+      _bazelCandidateFiles.add(BazelFileNotification(
+          relative, generatedCandidates.toList(), provider));
       // Not generated, return the default one.
       return writableFile;
     } catch (_) {
@@ -613,3 +794,9 @@
     }
   }
 }
+
+class FileInfo {
+  String path;
+  int modified;
+  FileInfo(this.path, this.modified);
+}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index c14bbd5..7c09d2c 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -24,6 +24,7 @@
 dev_dependencies:
   analyzer_utilities:
     path: ../analyzer_utilities
+  async: ^2.0.0
   linter: any
   matcher: ^0.12.3
   pedantic: ^1.9.0
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index d07c1ac..ee34035 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -13,6 +13,9 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(AssignmentDriverResolutionTest);
     defineReflectiveTests(AssignmentDriverResolutionWithNullSafetyTest);
+    defineReflectiveTests(
+      AssignmentDriverResolutionWithNonFunctionTypeAliasesTest,
+    );
   });
 }
 
@@ -2572,6 +2575,49 @@
 }
 
 @reflectiveTest
+class AssignmentDriverResolutionWithNonFunctionTypeAliasesTest
+    extends PubPackageResolutionTest with WithNonFunctionTypeAliasesMixin {
+  test_prefixedIdentifier_typeAlias_static_compound() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  static int get x => 0;
+  static set x(int _) {}
+}
+
+typedef B = A;
+
+void f() {
+  B.x += 2;
+}
+''');
+
+    var assignment = findNode.assignment('x += 2');
+    assertAssignment(
+      assignment,
+      readElement: findElement.getter('x'),
+      readType: 'int',
+      writeElement: findElement.setter('x'),
+      writeType: 'int',
+      operatorElement: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'int',
+    );
+
+    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
+    assertSimpleIdentifierAssignmentTarget(
+      prefixed.identifier,
+      readElement: null,
+      writeElement: null,
+      type: 'dynamic',
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+}
+
+@reflectiveTest
 class AssignmentDriverResolutionWithNullSafetyTest
     extends PubPackageResolutionTest
     with WithNullSafetyMixin, AssignmentDriverResolutionTestCases {}
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index bdd82f2..4421117e 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -15,6 +15,9 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(MethodInvocationResolutionTest);
     defineReflectiveTests(MethodInvocationResolutionWithNullSafetyTest);
+    defineReflectiveTests(
+      MethodInvocationResolutionWithNonFunctionTypeAliasesTest,
+    );
   });
 }
 
@@ -2342,6 +2345,60 @@
 }
 
 @reflectiveTest
+class MethodInvocationResolutionWithNonFunctionTypeAliasesTest
+    extends PubPackageResolutionTest with WithNonFunctionTypeAliasesMixin {
+  test_hasReceiver_typeAlias_staticMethod() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  static void foo(int _) {}
+}
+
+typedef B = A;
+
+void f() {
+  B.foo(0);
+}
+''');
+
+    assertMethodInvocation(
+      findNode.methodInvocation('foo(0)'),
+      findElement.method('foo'),
+      'void Function(int)',
+    );
+
+    assertTypeAliasRef(
+      findNode.simple('B.foo'),
+      findElement.typeAlias('B'),
+    );
+  }
+
+  test_hasReceiver_typeAlias_staticMethod_generic() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {
+  static void foo(int _) {}
+}
+
+typedef B<T> = A<T>;
+
+void f() {
+  B.foo(0);
+}
+''');
+
+    assertMethodInvocation(
+      findNode.methodInvocation('foo(0)'),
+      findElement.method('foo'),
+      'void Function(int)',
+    );
+
+    assertTypeAliasRef(
+      findNode.simple('B.foo'),
+      findElement.typeAlias('B'),
+    );
+  }
+}
+
+@reflectiveTest
 class MethodInvocationResolutionWithNullSafetyTest
     extends PubPackageResolutionTest
     with WithNullSafetyMixin, MethodInvocationResolutionTestCases {
diff --git a/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart b/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
index 50f5527..b952a96 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
@@ -12,6 +12,9 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(PrefixedIdentifierResolutionTest);
     defineReflectiveTests(PrefixedIdentifierResolutionWithNullSafetyTest);
+    defineReflectiveTests(
+      PrefixedIdentifierResolutionWithNonFunctionTypeAliasesTest,
+    );
   });
 }
 
@@ -271,6 +274,42 @@
 }
 
 @reflectiveTest
+class PrefixedIdentifierResolutionWithNonFunctionTypeAliasesTest
+    extends PubPackageResolutionTest with WithNonFunctionTypeAliasesMixin {
+  test_hasReceiver_typeAlias_staticGetter() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  static int get foo => 0;
+}
+
+typedef B = A;
+
+void f() {
+  B.foo;
+}
+''');
+
+    assertPrefixedIdentifier(
+      findNode.prefixed('B.foo'),
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+
+    assertTypeAliasRef(
+      findNode.simple('B.foo'),
+      findElement.typeAlias('B'),
+    );
+
+    assertSimpleIdentifier(
+      findNode.simple('foo;'),
+      readElement: findElement.getter('foo'),
+      writeElement: null,
+      type: 'int',
+    );
+  }
+}
+
+@reflectiveTest
 class PrefixedIdentifierResolutionWithNullSafetyTest
     extends PrefixedIdentifierResolutionTest with WithNullSafetyMixin {
   test_deferredImportPrefix_loadLibrary_optIn_fromOptOut() async {
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 31bed01..3b735c3 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -760,6 +760,15 @@
     }
   }
 
+  /// Assert that the given [identifier] is a reference to a type alias, in the
+  /// form that is not a separate expression, e.g. in a static method
+  /// invocation like `C.staticMethod()`, or a type annotation `C c = null`.
+  void assertTypeAliasRef(
+      SimpleIdentifier identifier, TypeAliasElement expected) {
+    assertElement(identifier, expected);
+    assertTypeNull(identifier);
+  }
+
   void assertTypeArgumentTypes(
     InvocationExpression node,
     List<String> expected,
diff --git a/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart b/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart
index af8a61a..4c9ceb3 100644
--- a/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart
@@ -10,11 +10,22 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(TypeAliasCannotReferenceItselfTest);
+    defineReflectiveTests(
+      TypeAliasCannotReferenceItselfWithNonFunctionTypeAliasesTest,
+    );
   });
 }
 
 @reflectiveTest
 class TypeAliasCannotReferenceItselfTest extends PubPackageResolutionTest {
+  test_functionTypeAlias_typeParameterBounds() async {
+    await assertErrorsInCode('''
+typedef A<T extends A<int>>();
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 30),
+    ]);
+  }
+
   test_functionTypedParameter_returnType() async {
     await assertErrorsInCode('''
 typedef A(A b());
@@ -37,6 +48,14 @@
     ]);
   }
 
+  test_genericTypeAlias_typeParameterBounds() async {
+    await assertErrorsInCode('''
+typedef A<T extends A<int>> = void Function();
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 46),
+    ]);
+  }
+
   test_infiniteParameterBoundCycle() async {
     await assertErrorsInCode(r'''
 typedef F<X extends F<X>> = F Function();
@@ -141,12 +160,58 @@
       error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 15, 14),
     ]);
   }
+}
 
-  test_typeVariableBounds() async {
+@reflectiveTest
+class TypeAliasCannotReferenceItselfWithNonFunctionTypeAliasesTest
+    extends PubPackageResolutionTest with WithNonFunctionTypeAliasesMixin {
+  test_nonFunction_aliasedType_cycleOf2() async {
     await assertErrorsInCode('''
-typedef A<T extends A<int>>();
+typedef T1 = T2;
+typedef T2 = T1;
 ''', [
-      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 30),
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 16),
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 17, 16),
+    ]);
+  }
+
+  test_nonFunction_aliasedType_directly_functionWithIt() async {
+    await assertErrorsInCode('''
+typedef T = void Function(T);
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 29),
+    ]);
+  }
+
+  test_nonFunction_aliasedType_directly_it_none() async {
+    await assertErrorsInCode('''
+typedef T = T;
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 14),
+    ]);
+  }
+
+  test_nonFunction_aliasedType_directly_it_question() async {
+    await assertErrorsInCode('''
+typedef T = T?;
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 15),
+    ]);
+  }
+
+  test_nonFunction_aliasedType_directly_ListOfIt() async {
+    await assertErrorsInCode('''
+typedef T = List<T>;
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 20),
+    ]);
+  }
+
+  test_nonFunction_typeParameterBounds() async {
+    await assertErrorsInCode('''
+typedef T<X extends T<Never>> = List<X>;
+''', [
+      error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 40),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 7ff0b3a..f3e7722 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -10690,7 +10690,7 @@
 typedef F<T extends F> = void Function();
 ''');
     checkElementText(library, r'''
-notSimplyBounded typedef F<T extends void Function()> = void Function();
+notSimplyBounded typedef F<T extends dynamic Function()> = void Function();
 ''');
   }
 
diff --git a/pkg/analyzer/test/src/workspace/bazel_test.dart b/pkg/analyzer/test/src/workspace/bazel_test.dart
index 2129789..f64cfc9 100644
--- a/pkg/analyzer/test/src/workspace/bazel_test.dart
+++ b/pkg/analyzer/test/src/workspace/bazel_test.dart
@@ -2,13 +2,17 @@
 // 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:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:analyzer/src/workspace/bazel.dart';
+import 'package:async/async.dart';
 import 'package:meta/meta.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:watcher/watcher.dart';
 
 import '../../generated/test_support.dart';
 
@@ -766,6 +770,152 @@
 class BazelWorkspaceTest with ResourceProviderMixin {
   BazelWorkspace workspace;
 
+  void test_bazelFileWatcher() async {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
+    _MockTimer timer;
+    var timerFactory = (Duration _, void Function(Timer) callback) {
+      timer = _MockTimer(callback);
+      return timer;
+    };
+    var candidates = [
+      convertPath('/workspace/bazel-bin/my/module/test1.dart'),
+      convertPath('/workspace/bazel-genfiles/my/module/test1.dart'),
+    ];
+    var watcher = BazelFileWatcher(candidates, resourceProvider, Duration.zero,
+        Duration.zero, timerFactory);
+    var events = StreamQueue(watcher.events);
+    watcher.start();
+
+    // First do some tests with the first candidate path.
+    _addResources([candidates[0]]);
+    timer.triggerCallback();
+
+    var event = await events.next;
+    expect(event.type, ChangeType.ADD);
+    expect(event.path, candidates[0]);
+
+    modifyFile(candidates[0], 'const foo = 42;');
+    timer.triggerCallback();
+
+    event = await events.next;
+    expect(event.type, ChangeType.MODIFY);
+    expect(event.path, candidates[0]);
+
+    _deleteResources([candidates[0]]);
+    timer.triggerCallback();
+
+    event = await events.next;
+    expect(event.type, ChangeType.REMOVE);
+    expect(event.path, candidates[0]);
+
+    // Now check that if we add the *second* candidate, we'll get the
+    // notification for it.
+    _addResources([candidates[1]]);
+    timer.triggerCallback();
+
+    event = await events.next;
+    expect(event.type, ChangeType.ADD);
+    expect(event.path, candidates[1]);
+
+    watcher.stop();
+    expect(await events.rest.isEmpty, true);
+  }
+
+  void test_bazelFileWatcher_existingFile() async {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/bazel-bin/my/module/test1.dart',
+    ]);
+    BazelWorkspace workspace = BazelWorkspace.find(
+        resourceProvider, convertPath('/workspace/my/module'));
+    _MockTimer timer;
+    var timerFactory = (Duration _, void Function(Timer) callback) {
+      timer = _MockTimer(callback);
+      return timer;
+    };
+    var watcherCompleter = Completer<BazelFileWatcher>();
+    workspace.bazelCandidateFiles.listen((notification) =>
+        watcherCompleter.complete(notification.watcher(
+            pollingDelayLong: Duration.zero,
+            pollingDelayShort: Duration.zero,
+            timerFactory: timerFactory)));
+
+    var file1 =
+        workspace.findFile(convertPath('/workspace/my/module/test1.dart'));
+    expect(file1.exists, true);
+    var watcher = await watcherCompleter.future;
+    var events = StreamQueue(watcher.events);
+    watcher.start();
+
+    // Make sure that triggering the callback, will not generate extra events.
+    timer.triggerCallback();
+
+    var convertedPath =
+        convertPath('/workspace/bazel-bin/my/module/test1.dart');
+
+    // Change the file -- we should get a single MODIFY event and not an ADD
+    // event, since the file already existed.
+    modifyFile(convertedPath, 'const foo = 42;');
+    timer.triggerCallback();
+    var event = await events.next;
+
+    expect(event.type, ChangeType.MODIFY);
+    expect(event.path, convertedPath);
+
+    // But if we delete the file and then re-create it, we should get an ADD
+    // event (after the REMOVE one).
+    deleteFile(convertedPath);
+    timer.triggerCallback();
+    event = await events.next;
+
+    expect(event.type, ChangeType.REMOVE);
+    expect(event.path, convertedPath);
+
+    newFile(convertedPath);
+    timer.triggerCallback();
+    event = await events.next;
+
+    expect(event.type, ChangeType.ADD);
+    expect(event.path, convertedPath);
+
+    watcher.stop();
+    expect(await events.rest.isEmpty, true);
+  }
+
+  void test_bazelNotifications() async {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/bazel-bin/my/module/test1.dart',
+    ]);
+    BazelWorkspace workspace = BazelWorkspace.find(
+        resourceProvider, convertPath('/workspace/my/module'));
+    var notifications = StreamQueue(workspace.bazelCandidateFiles);
+
+    var file1 =
+        workspace.findFile(convertPath('/workspace/my/module/test1.dart'));
+    expect(file1.exists, true);
+    var notification = await notifications.next;
+    expect(notification.requested, convertPath('my/module/test1.dart'));
+    expect(
+        notification.candidates,
+        containsAll(
+            [convertPath('/workspace/bazel-bin/my/module/test1.dart')]));
+
+    var file2 =
+        workspace.findFile(convertPath('/workspace/my/module/test2.dart'));
+    expect(file2.exists, false);
+    notification = await notifications.next;
+    expect(notification.requested, convertPath('my/module/test2.dart'));
+    expect(
+        notification.candidates,
+        containsAll([
+          convertPath('/workspace/bazel-bin/my/module/test2.dart'),
+          convertPath('/workspace/bazel-genfiles/my/module/test2.dart'),
+        ]));
+  }
+
   void test_find_fail_notAbsolute() {
     expect(
         () =>
@@ -1015,6 +1165,17 @@
     }
   }
 
+  /// Create new files and directories from [paths].
+  void _deleteResources(List<String> paths) {
+    for (String path in paths) {
+      if (path.endsWith('/')) {
+        deleteFolder(path.substring(0, path.length - 1));
+      } else {
+        deleteFile(path);
+      }
+    }
+  }
+
   /// Expect that [BazelWorkspace.findFile], given [path], returns [equals].
   void _expectFindFile(String path, {@required String equals}) =>
       expect(workspace.findFile(convertPath(path)).path, convertPath(equals));
@@ -1031,3 +1192,20 @@
     throw StateError('Unexpected invocation of ${invocation.memberName}');
   }
 }
+
+class _MockTimer implements Timer {
+  final void Function(Timer) callback;
+
+  @override
+  bool isActive = true;
+
+  _MockTimer(this.callback);
+
+  @override
+  int get tick => throw UnimplementedError();
+
+  @override
+  void cancel() => isActive = false;
+
+  void triggerCallback() => callback(this);
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 8800d4c..87fed8f 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -5530,27 +5530,6 @@
   js_ast.Expression visitAsExpression(AsExpression node) {
     var fromExpr = node.operand;
     var jsFrom = _visitExpression(fromExpr);
-
-    // The `_EventStreamSubscription.cancel()` method dart:html returns null in
-    // weak mode. This causes unwanted warnings/failures when you turn on the
-    // weak mode warnings/errors so we remove these specific runtime casts.
-    // TODO(44157) Remove this workaround once it returns a consistent type.
-    if (_isWebLibrary(currentLibraryUri) && node.parent is ReturnStatement) {
-      var parent = node.parent;
-      while (parent != null && parent is! FunctionNode) {
-        parent = parent?.parent;
-      }
-      parent = parent?.parent;
-      if (parent is Procedure) {
-        if (parent.enclosingClass != null &&
-            parent.enclosingClass.name == '_EventStreamSubscription' &&
-            parent.name.name == 'cancel') {
-          // Ignore these casts and just emit the expression.
-          return jsFrom;
-        }
-      }
-    }
-
     var to = node.type;
     var from = fromExpr.getStaticType(_staticTypeContext);
 
diff --git a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
index d85029a..22d60a1 100644
--- a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
@@ -1,12 +1,12 @@
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '&': JSNumber.& (num Function(num)), int.& (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '<<': JSNumber.<< (num Function(num)), int.<< (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1561|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
-ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1563|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1723|28|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1725|27|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1728|17|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1733|18|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1733|44|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1718|7|5|Superinterfaces don't have a valid override for '&': JSNumber.& (num Function(num)), int.& (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1718|7|5|Superinterfaces don't have a valid override for '<<': JSNumber.<< (num Function(num)), int.<< (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1718|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1718|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1718|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1573|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1575|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1735|28|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1737|27|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1740|17|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1745|18|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1745|44|1|The operator '&' isn't defined for the type 'JSInt'.
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 3a41006..85286cb 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -634,11 +634,7 @@
     char* error = nullptr;
 
     auto group = state_->isolate_group();
-#if defined(DART_PRECOMPILED_RUNTIME)
-    Isolate* isolate = CreateWithinExistingIsolateGroupAOT(group, name, &error);
-#else
     Isolate* isolate = CreateWithinExistingIsolateGroup(group, name, &error);
-#endif
     parent_isolate_->DecrementSpawnCount();
     parent_isolate_ = nullptr;
 
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 9f63a72..7100f1a 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -687,28 +687,17 @@
   return isolate;
 }
 
-#if defined(DART_PRECOMPILED_RUNTIME)
-static bool CloneIntoChildIsolateAOT(Thread* T,
-                                     Isolate* I,
-                                     IsolateGroup* source_isolate_group) {
-  // In AOT we speed up isolate spawning by copying donor's isolate structure.
-  if (source_isolate_group == nullptr) {
-    return false;
-  }
-  I->isolate_object_store()->Init();
-  I->isolate_object_store()->PreallocateObjects();
-  I->set_field_table(T, source_isolate_group->initial_field_table()->Clone(I));
-
-  return true;
-}
-#endif
-
 ErrorPtr Dart::InitIsolateFromSnapshot(Thread* T,
                                        Isolate* I,
                                        const uint8_t* snapshot_data,
                                        const uint8_t* snapshot_instructions,
                                        const uint8_t* kernel_buffer,
                                        intptr_t kernel_buffer_size) {
+  if (kernel_buffer != nullptr) {
+    SafepointReadRwLocker reader(T, I->group()->program_lock());
+    I->field_table()->MarkReadyToUse();
+  }
+
   Error& error = Error::Handle(T->zone());
   error = Object::Init(I, kernel_buffer, kernel_buffer_size);
   if (!error.IsNull()) {
@@ -742,7 +731,11 @@
       return error.raw();
     }
 
-    I->set_field_table(T, I->group()->initial_field_table()->Clone(I));
+    {
+      SafepointReadRwLocker reader(T, I->group()->program_lock());
+      I->set_field_table(T, I->group()->initial_field_table()->Clone(I));
+      I->field_table()->MarkReadyToUse();
+    }
 
 #if defined(SUPPORT_TIMELINE)
     if (tbes.enabled()) {
@@ -883,37 +876,58 @@
   StackZone zone(T);
   HandleScope handle_scope(T);
   bool was_child_cloned_into_existing_isolate = false;
-#if defined(DART_PRECOMPILED_RUNTIME)
-  if (CloneIntoChildIsolateAOT(T, I, source_isolate_group)) {
+  if (source_isolate_group != nullptr) {
+    I->isolate_object_store()->Init();
+    I->isolate_object_store()->PreallocateObjects();
+
+    // If a static field gets registered in [IsolateGroup::RegisterStaticField]:
+    //
+    //   * before this block it will ignore this isolate. The [Clone] of the
+    //     initial field table will pick up the new value.
+    //   * after this block it will add the new static field to this isolate.
+    {
+      SafepointReadRwLocker reader(T, source_isolate_group->program_lock());
+      I->set_field_table(T,
+                         source_isolate_group->initial_field_table()->Clone(I));
+      I->field_table()->MarkReadyToUse();
+    }
+
     was_child_cloned_into_existing_isolate = true;
   } else {
-#endif
     const Error& error = Error::Handle(
         InitIsolateFromSnapshot(T, I, snapshot_data, snapshot_instructions,
                                 kernel_buffer, kernel_buffer_size));
     if (!error.IsNull()) {
       return error.raw();
     }
-#if defined(DART_PRECOMPILED_RUNTIME)
   }
-#endif
 
   Object::VerifyBuiltinVtables();
   DEBUG_ONLY(I->heap()->Verify(kForbidMarked));
 
 #if defined(DART_PRECOMPILED_RUNTIME)
-  ASSERT(I->object_store()->build_method_extractor_code() != Code::null());
-  if (FLAG_print_llvm_constant_pool) {
-    PrintLLVMConstantPool(T, I);
-  }
+  const bool kIsAotRuntime = true;
 #else
-#if !defined(TARGET_ARCH_IA32)
-  if (I != Dart::vm_isolate()) {
-    I->object_store()->set_build_method_extractor_code(
-        Code::Handle(StubCode::GetBuildMethodExtractorStub(nullptr)));
-  }
+  const bool kIsAotRuntime = false;
 #endif
+
+  if (kIsAotRuntime || was_child_cloned_into_existing_isolate) {
+#if !defined(TARGET_ARCH_IA32)
+    ASSERT(I->object_store()->build_method_extractor_code() != Code::null());
+#endif
+#if defined(DART_PRECOMPILED_RUNTIME)
+    if (FLAG_print_llvm_constant_pool) {
+      PrintLLVMConstantPool(T, I);
+    }
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
+  } else {
+#if !defined(TARGET_ARCH_IA32)
+    if (I != Dart::vm_isolate()) {
+      I->object_store()->set_build_method_extractor_code(
+          Code::Handle(StubCode::GetBuildMethodExtractorStub(nullptr)));
+    }
+#endif  // !defined(TARGET_ARCH_IA32)
+  }
 
   I->set_ic_miss_code(StubCode::SwitchableCallMiss());
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 92fa101..60f008d 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1308,10 +1308,9 @@
   return false;
 }
 
-Isolate* CreateWithinExistingIsolateGroupAOT(IsolateGroup* group,
-                                             const char* name,
-                                             char** error) {
-#if defined(DART_PRECOMPILED_RUNTIME)
+Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
+                                          const char* name,
+                                          char** error) {
   API_TIMELINE_DURATION(Thread::Current());
   CHECK_NO_ISOLATE(Isolate::Current());
 
@@ -1326,171 +1325,6 @@
   ASSERT(isolate->source() == source);
 
   return isolate;
-#else
-  UNREACHABLE();
-#endif
-}
-
-Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
-                                          const char* name,
-                                          char** error) {
-#if !defined(DART_PRECOMPILED_RUNTIME)
-  API_TIMELINE_DURATION(Thread::Current());
-  CHECK_NO_ISOLATE(Isolate::Current());
-
-  // During isolate start we'll make a temporary anonymous group from the same
-  // [source]. Once the isolate has been fully loaded we will merge it's heap
-  // into the shared heap.
-  auto spawning_group = new IsolateGroup(group->shareable_source(),
-                                         /*isolate_group_data=*/nullptr);
-  IsolateGroup::RegisterIsolateGroup(spawning_group);
-  spawning_group->CreateHeap(
-      /*is_vm_isolate=*/false,
-      IsServiceOrKernelIsolateName(group->source()->name));
-
-  Isolate* isolate = reinterpret_cast<Isolate*>(
-      CreateIsolate(spawning_group, /*is_new_group=*/false, name,
-                    /*isolate_data=*/nullptr, error));
-  if (isolate == nullptr) return nullptr;
-
-  auto source = spawning_group->source();
-  ASSERT(isolate->source() == source);
-
-  if (source->script_kernel_buffer != nullptr) {
-    Dart_EnterScope();
-    {
-      Thread* T = Thread::Current();
-      TransitionNativeToVM transition(T);
-      HANDLESCOPE(T);
-      StackZone zone(T);
-
-      // NOTE: We do not attach a finalizer for this object, because the
-      // embedder will free it once the isolate group has shutdown.
-      const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
-          kExternalTypedDataUint8ArrayCid,
-          const_cast<uint8_t*>(source->script_kernel_buffer),
-          source->script_kernel_size, Heap::kOld));
-
-      std::unique_ptr<kernel::Program> program =
-          kernel::Program::ReadFromTypedData(td,
-                                             const_cast<const char**>(error));
-      if (program == nullptr) {
-        UNIMPLEMENTED();
-      }
-      const Object& tmp =
-          kernel::KernelLoader::LoadEntireProgram(program.get());
-
-      // If the existing isolate could spawn with a root library we should be
-      // able to do the same
-      RELEASE_ASSERT(!tmp.IsNull() && tmp.IsLibrary());
-      isolate->object_store()->set_root_library(Library::Cast(tmp));
-    }
-    Dart_ExitScope();
-  }
-
-  // If we are running in AppJIT training mode we'll have to remap class ids.
-  if (auto permutation_map = group->source()->cid_permutation_map.get()) {
-    Dart_EnterScope();
-    {
-      auto T = Thread::Current();
-      TransitionNativeToVM transition(T);
-      HANDLESCOPE(T);
-
-      // Remap all class ids loaded atm (e.g. from snapshot) and do appropriate
-      // re-hashing of constants and types.
-      ClassFinalizer::RemapClassIds(permutation_map);
-      // Types use cid's as part of their hashes.
-      ClassFinalizer::RehashTypes();
-      // Const objects use cid's as part of their hashes.
-      isolate->RehashConstants();
-    }
-    Dart_ExitScope();
-  }
-
-  auto thread = Thread::Current();
-  {
-    TransitionNativeToVM native_to_vm(thread);
-
-    // Ensure there are no helper threads running.
-    BackgroundCompiler::Stop(isolate);
-    isolate->heap()->WaitForMarkerTasks(thread);
-    isolate->heap()->WaitForSweeperTasks(thread);
-    SafepointOperationScope safepoint_operation(thread);
-    isolate->group()->ReleaseStoreBuffers();
-    RELEASE_ASSERT(isolate->heap()->old_space()->tasks() == 0);
-  }
-
-  Dart_ExitIsolate();
-  {
-    const bool kBypassSafepoint = false;
-    Thread::EnterIsolateGroupAsHelper(group, Thread::kUnknownTask,
-                                      kBypassSafepoint);
-    ASSERT(group == IsolateGroup::Current());
-
-    {
-      auto thread = Thread::Current();
-
-      // Prevent additions of new isolates to [group] until we're done.
-      group->RunWithLockedGroup([&]() {
-        // Ensure no other old space GC tasks are running and "occupy" the old
-        // space.
-        SafepointOperationScope safepoint_scope(thread);
-        {
-          auto old_space = group->heap()->old_space();
-          MonitorLocker ml(old_space->tasks_lock());
-          while (old_space->tasks() > 0) {
-            ml.Wait();
-          }
-          old_space->set_tasks(1);
-        }
-
-        // Merge the heap from [spawning_group] to [group].
-        group->heap()->MergeFrom(isolate->group()->heap());
-
-        spawning_group->UnregisterIsolate(isolate);
-        const bool shutdown_group =
-            spawning_group->UnregisterIsolateDecrementCount(isolate);
-        ASSERT(shutdown_group);
-
-        isolate->isolate_group_ = group;
-        group->RegisterIsolateLocked(isolate);
-        isolate->class_table()->shared_class_table_ =
-            group->shared_class_table();
-        isolate->set_shared_class_table(group->shared_class_table());
-
-        // Even though the mutator thread was descheduled, it will still
-        // retain its [Thread] structure with valid isolate/isolate_group
-        // pointers.
-        // If GC happens before the mutator gets scheduled again, we have to
-        // ensure the isolate group change is reflected in the threads
-        // structure.
-        ASSERT(isolate->mutator_thread() != nullptr);
-        ASSERT(isolate->mutator_thread()->isolate_group() == spawning_group);
-        isolate->mutator_thread()->isolate_group_ = group;
-
-        // Allow other old space GC tasks to run again.
-        {
-          auto old_space = group->heap()->old_space();
-          MonitorLocker ml(old_space->tasks_lock());
-          ASSERT(old_space->tasks() == 1);
-          old_space->set_tasks(0);
-          ml.NotifyAll();
-        }
-      });
-    }
-
-    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
-  }
-
-  spawning_group->Shutdown();
-
-  Dart_EnterIsolate(Api::CastIsolate(isolate));
-  ASSERT(Thread::Current()->isolate_group() == isolate->group());
-
-  return isolate;
-#else
-  UNREACHABLE();
-#endif
 }
 
 DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags) {
@@ -1589,7 +1423,7 @@
 
   Isolate* isolate;
 #if defined(DART_PRECOMPILED_RUNTIME)
-  isolate = CreateWithinExistingIsolateGroupAOT(member->group(), name, error);
+  isolate = CreateWithinExistingIsolateGroup(member->group(), name, error);
   if (isolate != nullptr) {
     isolate->set_origin_id(member->origin_id());
     isolate->set_init_callback_data(child_isolate_data);
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 80f0462..7c58510 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -353,9 +353,6 @@
 Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
                                           const char* name,
                                           char** error);
-Isolate* CreateWithinExistingIsolateGroupAOT(IsolateGroup* group,
-                                             const char* name,
-                                             char** error);
 
 }  // namespace dart.
 
diff --git a/runtime/vm/field_table.cc b/runtime/vm/field_table.cc
index a6358a1..fe40d10 100644
--- a/runtime/vm/field_table.cc
+++ b/runtime/vm/field_table.cc
@@ -22,6 +22,25 @@
   free(table_);        // Allocated in FieldTable::Grow()
 }
 
+bool FieldTable::IsReadyToUse() const {
+  DEBUG_ASSERT(
+      IsolateGroup::Current()->program_lock()->IsCurrentThreadReader());
+  return is_ready_to_use_;
+}
+
+void FieldTable::MarkReadyToUse() {
+  // The isolate will mark it's field table ready-to-use upon initialization of
+  // the isolate. Only after it was marked as ready-to-use will it participate
+  // in new static field registrations.
+  //
+  // By requiring a read lock here we ensure no other thread is is registering a
+  // new static field at this moment (it would need exlusive writer lock).
+  DEBUG_ASSERT(
+      IsolateGroup::Current()->program_lock()->IsCurrentThreadReader());
+  ASSERT(!is_ready_to_use_);
+  is_ready_to_use_ = true;
+}
+
 void FieldTable::FreeOldTables() {
   while (old_tables_->length() > 0) {
     free(old_tables_->RemoveLast());
@@ -32,21 +51,27 @@
   return field_id * sizeof(InstancePtr);  // NOLINT
 }
 
-void FieldTable::Register(const Field& field) {
+bool FieldTable::Register(const Field& field, intptr_t expected_field_id) {
+  DEBUG_ASSERT(
+      IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
   ASSERT(Thread::Current()->IsMutatorThread());
+  ASSERT(is_ready_to_use_);
+
   if (free_head_ < 0) {
+    bool grown_backing_store = false;
     if (top_ == capacity_) {
       const intptr_t new_capacity = capacity_ + kCapacityIncrement;
       Grow(new_capacity);
+      grown_backing_store = true;
     }
 
     ASSERT(top_ < capacity_);
-
+    ASSERT(expected_field_id == -1 || expected_field_id == top_);
     field.set_field_id(top_);
     table_[top_] = Object::sentinel().raw();
 
     ++top_;
-    return;
+    return grown_backing_store;
   }
 
   // Reuse existing free element. This is "slow path" that should only be
@@ -55,6 +80,7 @@
   free_head_ = Smi::Value(Smi::RawCast(table_[free_head_]));
   field.set_field_id(reused_free);
   table_[reused_free] = Object::sentinel().raw();
+  return false;
 }
 
 void FieldTable::Free(intptr_t field_id) {
@@ -104,6 +130,9 @@
 }
 
 FieldTable* FieldTable::Clone(Isolate* for_isolate) {
+  DEBUG_ASSERT(
+      IsolateGroup::Current()->program_lock()->IsCurrentThreadReader());
+
   FieldTable* clone = new FieldTable(for_isolate);
   auto new_table = static_cast<InstancePtr*>(
       malloc(capacity_ * sizeof(InstancePtr)));  // NOLINT
diff --git a/runtime/vm/field_table.h b/runtime/vm/field_table.h
index 4fc1ca8..4350745 100644
--- a/runtime/vm/field_table.h
+++ b/runtime/vm/field_table.h
@@ -27,10 +27,14 @@
         free_head_(-1),
         table_(nullptr),
         old_tables_(new MallocGrowableArray<InstancePtr*>()),
-        isolate_(isolate) {}
+        isolate_(isolate),
+        is_ready_to_use_(isolate == nullptr) {}
 
   ~FieldTable();
 
+  bool IsReadyToUse() const;
+  void MarkReadyToUse();
+
   intptr_t NumFieldIds() const { return top_; }
   intptr_t Capacity() const { return capacity_; }
 
@@ -43,7 +47,9 @@
 
   bool IsValidIndex(intptr_t index) const { return index >= 0 && index < top_; }
 
-  void Register(const Field& field);
+  // Returns whether registering this field caused a growth in the backing
+  // store.
+  bool Register(const Field& field, intptr_t expected_field_id = -1);
   void AllocateIndex(intptr_t index);
 
   // Static field elements are being freed only during isolate reload
@@ -89,6 +95,10 @@
   // mutator thread up-to-date.
   Isolate* isolate_;
 
+  // Whether this field table is ready to use by e.g. registering new static
+  // fields.
+  bool is_ready_to_use_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(FieldTable);
 };
 
diff --git a/runtime/vm/heap/freelist.cc b/runtime/vm/heap/freelist.cc
index 2923aee..e2fd5f8 100644
--- a/runtime/vm/heap/freelist.cc
+++ b/runtime/vm/heap/freelist.cc
@@ -373,41 +373,4 @@
   return NULL;
 }
 
-void FreeList::MergeFrom(FreeList* donor, bool is_protected) {
-  // The [other] free list is from a dying isolate. There are no other threads
-  // accessing it, so there is no need to lock here.
-  MutexLocker ml(&mutex_);
-  for (intptr_t i = 0; i < (kNumLists + 1); ++i) {
-    FreeListElement* donor_head = donor->free_lists_[i];
-    if (donor_head != nullptr) {
-      // If we didn't have a freelist element before we have to set the bit now,
-      // since we will get 1+ elements from [other].
-      FreeListElement* old_head = free_lists_[i];
-      if (old_head == nullptr && i != kNumLists) {
-        free_map_.Set(i, true);
-      }
-
-      // Chain other's list in.
-      FreeListElement* last = donor_head;
-      while (last->next() != nullptr) {
-        last = last->next();
-      }
-
-      if (is_protected) {
-        VirtualMemory::Protect(reinterpret_cast<void*>(last), sizeof(*last),
-                               VirtualMemory::kReadWrite);
-      }
-      last->set_next(old_head);
-      if (is_protected) {
-        VirtualMemory::Protect(reinterpret_cast<void*>(last), sizeof(*last),
-                               VirtualMemory::kReadExecute);
-      }
-      free_lists_[i] = donor_head;
-    }
-  }
-
-  last_free_small_size_ =
-      Utils::Maximum(last_free_small_size_, donor->last_free_small_size_);
-}
-
 }  // namespace dart
diff --git a/runtime/vm/heap/freelist.h b/runtime/vm/heap/freelist.h
index 677a0f2..b868c19 100644
--- a/runtime/vm/heap/freelist.h
+++ b/runtime/vm/heap/freelist.h
@@ -154,8 +154,6 @@
   void set_end(uword value) { end_ = value; }
   void AddUnaccountedSize(intptr_t size) { unaccounted_size_ += size; }
 
-  void MergeFrom(FreeList* donor, bool is_protected);
-
  private:
   static const int kNumLists = 128;
   static const intptr_t kInitialFreeListSearchBudget = 1000;
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index a1d5866..e5c2426 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -717,30 +717,6 @@
   gc_on_nth_allocation_ = num_allocations;
 }
 
-void Heap::MergeFrom(Heap* donor) {
-  ASSERT(!donor->read_only_);
-  ASSERT(donor->old_space()->tasks() == 0);
-
-  new_space_.MergeFrom(donor->new_space());
-  old_space_.MergeFrom(donor->old_space());
-
-  for (intptr_t i = 0; i < kNumWeakSelectors; ++i) {
-    // The new space rehashing should not be necessary.
-    new_weak_tables_[i]->MergeFrom(donor->new_weak_tables_[i]);
-    old_weak_tables_[i]->MergeFrom(donor->old_weak_tables_[i]);
-  }
-
-  StoreBufferBlock* block =
-      donor->isolate_group()->store_buffer()->TakeBlocks();
-  while (block != nullptr) {
-    StoreBufferBlock* next = block->next();
-    block->set_next(nullptr);
-    isolate_group()->store_buffer()->PushBlock(block,
-                                               StoreBuffer::kIgnoreThreshold);
-    block = next;
-  }
-}
-
 void Heap::CollectForDebugging() {
   if (gc_on_nth_allocation_ == kNoForcedGarbageCollection) return;
   if (Thread::Current()->IsAtSafepoint()) {
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 026d793..f303a15 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -322,8 +322,6 @@
 
   void CollectOnNthAllocation(intptr_t num_allocations);
 
-  void MergeFrom(Heap* donor);
-
  private:
   class GCStats : public ValueObject {
    public:
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index d3b62fa..39180e8 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -1447,95 +1447,6 @@
   return false;
 }
 
-static void AppendList(OldPage** pages,
-                       OldPage** pages_tail,
-                       OldPage** other_pages,
-                       OldPage** other_pages_tail) {
-  ASSERT((*pages == nullptr) == (*pages_tail == nullptr));
-  ASSERT((*other_pages == nullptr) == (*other_pages_tail == nullptr));
-
-  if (*other_pages != nullptr) {
-    if (*pages_tail == nullptr) {
-      *pages = *other_pages;
-      *pages_tail = *other_pages_tail;
-    } else {
-      const bool is_execute = FLAG_write_protect_code &&
-                              (*pages_tail)->type() == OldPage::kExecutable;
-      if (is_execute) {
-        (*pages_tail)->WriteProtect(false);
-      }
-      (*pages_tail)->set_next(*other_pages);
-      if (is_execute) {
-        (*pages_tail)->WriteProtect(true);
-      }
-      *pages_tail = *other_pages_tail;
-    }
-    *other_pages = nullptr;
-    *other_pages_tail = nullptr;
-  }
-}
-
-static void EnsureEqualImagePages(OldPage* pages, OldPage* other_pages) {
-#if defined(DEBUG)
-  while (pages != nullptr) {
-    ASSERT((pages == nullptr) == (other_pages == nullptr));
-    ASSERT(pages->object_start() == other_pages->object_start());
-    ASSERT(pages->object_end() == other_pages->object_end());
-    pages = pages->next();
-    other_pages = other_pages->next();
-  }
-#endif
-}
-
-void PageSpace::MergeFrom(PageSpace* donor) {
-  donor->AbandonBumpAllocation();
-
-  ASSERT(donor->tasks_ == 0);
-  ASSERT(donor->concurrent_marker_tasks_ == 0);
-  ASSERT(donor->phase_ == kDone);
-  DEBUG_ASSERT(donor->iterating_thread_ == nullptr);
-  ASSERT(donor->marker_ == nullptr);
-
-  for (intptr_t i = 0; i < num_freelists_; ++i) {
-    ASSERT(donor->freelists_[i].top() == 0);
-    ASSERT(donor->freelists_[i].end() == 0);
-    const bool is_protected =
-        FLAG_write_protect_code && i == OldPage::kExecutable;
-    freelists_[i].MergeFrom(&donor->freelists_[i], is_protected);
-    donor->freelists_[i].Reset();
-  }
-
-  // The freelist locks will be taken in MergeOtherFreelist above, and the
-  // locking order is the freelist locks are taken before the page list locks,
-  // so don't take the pages lock until after MergeOtherFreelist.
-  MutexLocker ml(&pages_lock_);
-  MutexLocker ml2(&donor->pages_lock_);
-
-  AppendList(&pages_, &pages_tail_, &donor->pages_, &donor->pages_tail_);
-  AppendList(&exec_pages_, &exec_pages_tail_, &donor->exec_pages_,
-             &donor->exec_pages_tail_);
-  AppendList(&large_pages_, &large_pages_tail_, &donor->large_pages_,
-             &donor->large_pages_tail_);
-  // We intentionall do not merge [image_pages_] beause [this] and [other] have
-  // the same mmap()ed image page areas.
-  EnsureEqualImagePages(image_pages_, donor->image_pages_);
-
-  // We intentionaly do not increase [max_capacity_in_words_] because this can
-  // lead [max_capacity_in_words_] to become larger and larger and eventually
-  // wrap-around and become negative.
-  allocated_black_in_words_ += donor->allocated_black_in_words_;
-  gc_time_micros_ += donor->gc_time_micros_;
-  collections_ += donor->collections_;
-
-  usage_.capacity_in_words += donor->usage_.capacity_in_words;
-  usage_.used_in_words += donor->usage_.used_in_words;
-  usage_.external_in_words += donor->usage_.external_in_words;
-
-  page_space_controller_.MergeFrom(&donor->page_space_controller_);
-
-  ASSERT(FLAG_concurrent_mark || donor->enable_concurrent_mark_ == false);
-}
-
 PageSpaceController::PageSpaceController(Heap* heap,
                                          int heap_growth_ratio,
                                          int heap_growth_max,
@@ -1771,12 +1682,6 @@
   // TODO(rmacnak): Hasten the soft threshold at some discount?
 }
 
-void PageSpaceController::MergeFrom(PageSpaceController* donor) {
-  last_usage_.capacity_in_words += donor->last_usage_.capacity_in_words;
-  last_usage_.used_in_words += donor->last_usage_.used_in_words;
-  last_usage_.external_in_words += donor->last_usage_.external_in_words;
-}
-
 void PageSpaceGarbageCollectionHistory::AddGarbageCollectionTime(int64_t start,
                                                                  int64_t end) {
   Entry entry;
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index a786f78..434ad7f 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -240,8 +240,6 @@
   friend class PageSpace;  // For MergeOtherPageSpaceController
 
   void RecordUpdate(SpaceUsage before, SpaceUsage after, const char* reason);
-  void MergeFrom(PageSpaceController* donor);
-
   void RecordUpdate(SpaceUsage before,
                     SpaceUsage after,
                     intptr_t growth_in_pages,
@@ -489,8 +487,6 @@
 
   bool IsObjectFromImagePages(ObjectPtr object);
 
-  void MergeFrom(PageSpace* donor);
-
  private:
   // Ids for time and data records in Heap::GCStats.
   enum {
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 3f6f09d..f22ab54 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -715,19 +715,6 @@
   tail_ = tail;
 }
 
-void SemiSpace::MergeFrom(SemiSpace* donor) {
-  for (NewPage* page = donor->head_; page != nullptr; page = page->next()) {
-    page->Release();
-  }
-
-  AddList(donor->head_, donor->tail_);
-  capacity_in_words_ += donor->capacity_in_words_;
-
-  donor->head_ = nullptr;
-  donor->tail_ = nullptr;
-  donor->capacity_in_words_ = 0;
-}
-
 // The initial estimate of how many words we can scavenge per microsecond (usage
 // before / scavenge time). This is a conservative value observed running
 // Flutter on a Nexus 4. After the first scavenge, we instead use a value based
@@ -1721,13 +1708,4 @@
   ASSERT((UsedInWords() == 0) || failed_to_promote_);
 }
 
-void Scavenger::MergeFrom(Scavenger* donor) {
-  MutexLocker ml(&space_lock_);
-  MutexLocker ml2(&donor->space_lock_);
-  to_->MergeFrom(donor->to_);
-
-  external_size_ += donor->external_size_;
-  donor->external_size_ = 0;
-}
-
 }  // namespace dart
diff --git a/runtime/vm/heap/scavenger.h b/runtime/vm/heap/scavenger.h
index 5e7486b..785825e 100644
--- a/runtime/vm/heap/scavenger.h
+++ b/runtime/vm/heap/scavenger.h
@@ -184,7 +184,6 @@
   NewPage* head() const { return head_; }
 
   void AddList(NewPage* head, NewPage* tail);
-  void MergeFrom(SemiSpace* donor);
 
  private:
   // Size of NewPages in this semi-space.
@@ -281,8 +280,6 @@
   // Promote all live objects.
   void Evacuate();
 
-  void MergeFrom(Scavenger* donor);
-
   int64_t UsedInWords() const {
     MutexLocker ml(&space_lock_);
     return to_->capacity_in_words();
diff --git a/runtime/vm/heap/weak_table.cc b/runtime/vm/heap/weak_table.cc
index fdb0a7d..4070590 100644
--- a/runtime/vm/heap/weak_table.cc
+++ b/runtime/vm/heap/weak_table.cc
@@ -140,12 +140,4 @@
   free(old_data);
 }
 
-void WeakTable::MergeFrom(WeakTable* donor) {
-  for (intptr_t i = 0; i < donor->size(); i++) {
-    if (donor->IsValidEntryAtExclusive(i)) {
-      SetValueExclusive(donor->ObjectAtExclusive(i), ValueIndex(i));
-    }
-  }
-}
-
 }  // namespace dart
diff --git a/runtime/vm/heap/weak_table.h b/runtime/vm/heap/weak_table.h
index c7728b0..c72d773 100644
--- a/runtime/vm/heap/weak_table.h
+++ b/runtime/vm/heap/weak_table.h
@@ -133,8 +133,6 @@
 
   void Reset();
 
-  void MergeFrom(WeakTable* donor);
-
  private:
   enum {
     kObjectOffset = 0,
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 4500d86..7f229b7 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -345,11 +345,7 @@
       safepoint_handler_(new SafepointHandler(this)),
       shared_class_table_(new SharedClassTable()),
       object_store_(object_store),
-#if defined(DART_PRECOMPILED_RUNTIME)
       class_table_(new ClassTable(shared_class_table_.get())),
-#else
-      class_table_(nullptr),
-#endif
       store_buffer_(new StoreBuffer()),
       heap_(nullptr),
       saved_unlinked_calls_(Array::null()),
@@ -393,14 +389,7 @@
 
 IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
                            void* embedder_data)
-    : IsolateGroup(source,
-                   embedder_data,
-#if !defined(DART_PRECOMPILED_RUNTIME)
-                   // in JIT, with --enable_isolate_groups keep object store
-                   // on isolate, rather than on isolate group
-                   FLAG_enable_isolate_groups ? nullptr :
-#endif
-                                              new ObjectStore()) {
+    : IsolateGroup(source, embedder_data, new ObjectStore()) {
   if (object_store() != nullptr) {
     object_store()->InitStubs();
   }
@@ -908,15 +897,31 @@
   ASSERT(program_lock()->IsCurrentThreadWriter());
 
   ASSERT(field.is_static());
-  initial_field_table()->Register(field);
-  initial_field_table()->SetAt(field.field_id(), initial_value.raw());
+  const bool need_to_grow_backing_store =
+      initial_field_table()->Register(field);
+  const intptr_t field_id = field.field_id();
+  initial_field_table()->SetAt(field_id, initial_value.raw());
 
-  // TODO(dartbug.com/36097): When we start sharing the object stores (and
-  // therefore libraries, classes, fields) we'll have to register the initial
-  // static field value in all isolates.
-  auto current = Isolate::Current();
-  current->field_table()->AllocateIndex(field.field_id());
-  current->field_table()->SetAt(field.field_id(), initial_value.raw());
+  if (need_to_grow_backing_store) {
+    // We have to stop other isolates from accessing their field state, since
+    // we'll have to grow the backing store.
+    SafepointOperationScope ops(Thread::Current());
+    for (auto isolate : isolates_) {
+      auto field_table = isolate->field_table();
+      if (field_table->IsReadyToUse()) {
+        field_table->Register(field, field_id);
+        field_table->SetAt(field_id, initial_value.raw());
+      }
+    }
+  } else {
+    for (auto isolate : isolates_) {
+      auto field_table = isolate->field_table();
+      if (field_table->IsReadyToUse()) {
+        field_table->Register(field, field_id);
+        field_table->SetAt(field_id, initial_value.raw());
+      }
+    }
+  }
 }
 
 void Isolate::RehashConstants() {
@@ -1636,11 +1641,7 @@
       isolate_object_store_(
           new IsolateObjectStore(isolate_group->object_store())),
       object_store_shared_ptr_(isolate_group->object_store_shared_ptr()),
-#if defined(DART_PRECOMPILED_RUNTIME)
       class_table_(isolate_group->class_table_shared_ptr()),
-#else
-      class_table_(new ClassTable(shared_class_table_)),
-#endif
 #if !defined(DART_PRECOMPILED_RUNTIME)
       native_callback_trampolines_(),
 #endif
@@ -1773,12 +1774,7 @@
     // Non-vm isolates need to have isolate object store initialized is that
     // exit_listeners have to be null-initialized as they will be used if
     // we fail to create isolate below, have to do low level shutdown.
-    if (result->object_store() == nullptr) {
-      // in JIT with --enable-isolate-groups each isolate still
-      // has to have its own object store
-      result->set_object_store(new ObjectStore());
-      result->object_store()->InitStubs();
-    }
+    ASSERT(result->object_store() != nullptr);
     result->isolate_object_store()->Init();
   }
 
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e88229a..a3b1b8a 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -718,8 +718,8 @@
   uint64_t id_ = 0;
 
   std::unique_ptr<SharedClassTable> shared_class_table_;
-  std::shared_ptr<ObjectStore> object_store_;  // nullptr in JIT mode
-  std::shared_ptr<ClassTable> class_table_;    // nullptr in JIT mode
+  std::shared_ptr<ObjectStore> object_store_;
+  std::shared_ptr<ClassTable> class_table_;
   std::unique_ptr<StoreBuffer> store_buffer_;
   std::unique_ptr<Heap> heap_;
   std::unique_ptr<DispatchTable> dispatch_table_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e673c0a..acb3646 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -10731,16 +10731,23 @@
 
 void Field::SetStaticValue(const Instance& value,
                            bool save_initial_value) const {
-  ASSERT(Thread::Current()->IsMutatorThread());
+  auto thread = Thread::Current();
+  ASSERT(thread->IsMutatorThread());
 
   ASSERT(is_static());  // Valid only for static dart fields.
-  Isolate* isolate = Isolate::Current();
   const intptr_t id = field_id();
   ASSERT(id >= 0);
-  isolate->field_table()->SetAt(id, value.raw());
+
+  SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
+  thread->isolate()->field_table()->SetAt(id, value.raw());
   if (save_initial_value) {
+    // TODO(https://dartbug.com/36097): We should re-visit call-sites where
+    // `save_initial_value == true` and try to have a different path. This
+    // method should only modify the isolate-local field state and not modify
+    // the initial field table.
 #if !defined(DART_PRECOMPILED_RUNTIME)
-    isolate->group()->initial_field_table()->SetAt(field_id(), value.raw());
+    thread->isolate_group()->initial_field_table()->SetAt(field_id(),
+                                                          value.raw());
 #endif
   }
 }
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index 907dda1..4aab7f8 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -219,6 +219,12 @@
           if (update_values && !field.is_const()) {
             // Make new field point to the old field value so that both
             // old and new code see and update same value.
+            //
+            // TODO(https://dartbug.com/36097): Once we look into enabling
+            // hot-reload with --enable-isolate-groups we have to do this
+            // for all isolates.
+            reload_context->isolate()->group()->initial_field_table()->Free(
+                field.field_id());
             reload_context->isolate()->field_table()->Free(field.field_id());
             field.set_field_id(old_field.field_id());
           }
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 52f46f8..3364072 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -164,13 +164,8 @@
                                                 void* group_data,
                                                 void* isolate_data) {
   char* error;
-#if defined(DART_PRECOMPILED_RUNTIME)
-  Isolate* result = CreateWithinExistingIsolateGroupAOT(
-      reinterpret_cast<Isolate*>(parent)->group(), name, &error);
-#else
   Isolate* result = CreateWithinExistingIsolateGroup(
       reinterpret_cast<Isolate*>(parent)->group(), name, &error);
-#endif
   if (error != nullptr) {
     OS::PrintErr("CreateTestIsolateInGroup failed: %s\n", error);
     free(error);
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index 93bd80c..ffefd1f 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -282,15 +282,27 @@
   }
 
   void addAll(Iterable<E> collection) {
-    int i = this.length;
     checkGrowable('addAll');
+    if (collection is JSArray) {
+      _addAllFromArray(JS('', '#', collection));
+      return;
+    }
+    int i = this.length;
     for (E e in collection) {
-      assert(
-          i++ == this.length || (throw new ConcurrentModificationError(this)));
+      assert(i++ == this.length || (throw ConcurrentModificationError(this)));
       JS('void', r'#.push(#)', this, e);
     }
   }
 
+  void _addAllFromArray(JSArray array) {
+    int len = array.length;
+    if (len == 0) return;
+    if (identical(this, array)) throw ConcurrentModificationError(this);
+    for (int i = 0; i < len; i++) {
+      JS('', '#.push(#[#])', this, array, i);
+    }
+  }
+
   void clear() {
     length = 0;
   }
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index a79aff6..bc7bdfb 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -37285,18 +37285,13 @@
   }
 
   Future cancel() {
-    // Check for strong mode. This function can no longer return null in strong
-    // mode, so only return null in weak mode to preserve synchronous timing.
-    // See issue 41653 for more details.
-    dynamic emptyFuture =
-        typeAcceptsNull<Event>() ? null : Future<void>.value();
-    if (_canceled) return emptyFuture as Future;
+    if (_canceled) return nullFuture;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
-    return emptyFuture as Future;
+    return nullFuture;
   }
 
   bool get _canceled => _target == null;
diff --git a/tools/VERSION b/tools/VERSION
index 84ed07b..e263e32 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 135
+PRERELEASE 136
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index fe01be9..feadc26 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -248,18 +248,13 @@
   }
 
   Future cancel() {
-    // Check for strong mode. This function can no longer return null in strong
-    // mode, so only return null in weak mode to preserve synchronous timing.
-    // See issue 41653 for more details.
-    dynamic emptyFuture =
-        typeAcceptsNull<Event>() ? null : Future<void>.value();
-    if (_canceled) return emptyFuture as Future;
+    if (_canceled) return nullFuture;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
-    return emptyFuture as Future;
+    return nullFuture;
   }
 
   bool get _canceled => _target == null;