Version 2.11.0-226.0.dev

Merge commit '80f12af7e804c8a7dc9664eac7cedac3c9ba3a1d' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart b/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart
index 57531d9..9fd158d 100644
--- a/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart
+++ b/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart
@@ -5,6 +5,13 @@
 import 'package:analyzer/src/dart/analysis/cache.dart';
 import 'package:collection/collection.dart';
 
+class CacheData {
+  final int id;
+  final List<int> bytes;
+
+  CacheData(this.id, this.bytes);
+}
+
 /// Store of bytes associated with string keys and a hash.
 ///
 /// Each key must be not longer than 100 characters and consist of only `[a-z]`,
@@ -18,39 +25,52 @@
   /// [signature].
   ///
   /// Return `null` if the association does not exist.
-  List<int> get(String key, List<int> signature);
+  CacheData get(String key, List<int> signature);
 
-  /// Associate the given [bytes] with the [key] and [digest].
-  void put(String key, List<int> signature, List<int> bytes);
+  /// Associate the given [bytes] with the [key] and [signature]. Return the
+  /// [CacheData].
+  CacheData putGet(String key, List<int> signature, List<int> bytes);
+
+  ///  Used to decrement reference count for the given ids, if implemented.
+  void release(Iterable<int> ids);
 }
 
 class CiderCachedByteStore implements CiderByteStore {
   final Cache<String, CiderCacheEntry> _cache;
+  int idCounter = 0;
 
   CiderCachedByteStore(int maxCacheSize)
-      : _cache =
-            Cache<String, CiderCacheEntry>(maxCacheSize, (v) => v.bytes.length);
+      : _cache = Cache<String, CiderCacheEntry>(
+            maxCacheSize, (v) => v.data.bytes.length);
 
   @override
-  List<int> get(String key, List<int> signature) {
+  CacheData get(String key, List<int> signature) {
     var entry = _cache.get(key, () => null);
 
     if (entry != null &&
         const ListEquality<int>().equals(entry.signature, signature)) {
-      return entry.bytes;
+      return entry.data;
     }
     return null;
   }
 
   @override
-  void put(String key, List<int> signature, List<int> bytes) {
-    _cache.put(key, CiderCacheEntry(signature, bytes));
+  CacheData putGet(String key, List<int> signature, List<int> bytes) {
+    idCounter++;
+    var entry = CiderCacheEntry(signature, CacheData(idCounter, bytes));
+    _cache.put(key, entry);
+    return entry.data;
+  }
+
+  @override
+  void release(Iterable<int> ids) {
+    // do nothing
   }
 }
 
 class CiderCacheEntry {
+  final CacheData data;
   final List<int> signature;
-  final List<int> bytes;
 
-  CiderCacheEntry(this.signature, this.bytes);
+  CiderCacheEntry(this.signature, this.data);
 }
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index b870957..d116df5 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -90,6 +90,9 @@
   UnlinkedUnit2 unlinked2;
   LibraryCycle _libraryCycle;
 
+  /// id of the cache entry.
+  int id;
+
   FileState._(
     this._fsState,
     this.path,
@@ -219,7 +222,8 @@
     // Prepare bytes of the unlinked bundle - existing or new.
     List<int> bytes;
     {
-      bytes = _fsState._byteStore.get(unlinkedKey, _digest);
+      var cacheData = _fsState._byteStore.get(unlinkedKey, _digest);
+      bytes = cacheData?.bytes;
 
       if (bytes == null || bytes.isEmpty) {
         var content = performance.run('content', (_) {
@@ -236,7 +240,8 @@
           var unlinkedBuilder = serializeAstCiderUnlinked(_digest, unit);
           bytes = unlinkedBuilder.toBuffer();
           performance.getDataInt('length').add(bytes.length);
-          _fsState._byteStore.put(unlinkedKey, _digest, bytes);
+          cacheData = _fsState._byteStore.putGet(unlinkedKey, _digest, bytes);
+          bytes = cacheData.bytes;
         });
 
         performance.run('prefetch', (_) {
@@ -244,6 +249,7 @@
           _prefetchDirectReferences(unlinked2);
         });
       }
+      id = cacheData.id;
     }
 
     // Read the unlinked bundle.
@@ -645,6 +651,9 @@
   /// The hash of all the paths of the files in this cycle.
   String cyclePathsHash;
 
+  /// id of the cache entry.
+  int id;
+
   LibraryCycle();
 
   String get signatureStr {
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index bd7ab2fa..ab523a5 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -83,6 +83,11 @@
 
   _LibraryContext libraryContext;
 
+  /// List of ids for cache elements that are invalidated. Track elements that
+  /// are invalidated during [changeFile]. Used in [releaseAndClearRemovedIds] to
+  /// release the cache items and is then cleared.
+  final Set<int> removedCacheIds = {};
+
   FileResolver(
     PerformanceLog logger,
     ResourceProvider resourceProvider,
@@ -132,7 +137,8 @@
   /// Update the resolver to reflect the fact that the file with the given
   /// [path] was changed. We need to make sure that when this file, of any file
   /// that directly or indirectly referenced it, is resolved, we used the new
-  /// state of the file.
+  /// state of the file. Updates [removedCacheIds] with the ids of the invalidated
+  /// items, used in [releaseAndClearRemovedIds] to release the cache items.
   void changeFile(String path) {
     if (fsState == null) {
       return;
@@ -149,12 +155,13 @@
         path: removedFile.path,
         uri: removedFile.uri,
       );
+      removedCacheIds.add(removedFile.id);
     }
 
     // Remove libraries represented by removed files.
     // If we need these libraries later, we will relink and reattach them.
     if (libraryContext != null) {
-      libraryContext.remove(removedFiles);
+      libraryContext.remove(removedFiles, removedCacheIds);
     }
   }
 
@@ -184,7 +191,7 @@
         var errorsSignature = errorsSignatureBuilder.toByteList();
 
         var errorsKey = file.path + '.errors';
-        var bytes = byteStore.get(errorsKey, errorsSignature);
+        var bytes = byteStore.get(errorsKey, errorsSignature)?.bytes;
         List<AnalysisError> errors;
         if (bytes != null) {
           var data = CiderUnitErrors.fromBuffer(bytes);
@@ -204,7 +211,7 @@
             signature: errorsSignature,
             errors: errors.map(ErrorEncoding.encode).toList(),
           ).toBuffer();
-          byteStore.put(errorsKey, errorsSignature, bytes);
+          bytes = byteStore.putGet(errorsKey, errorsSignature, bytes).bytes;
         }
 
         return ErrorsResultImpl(
@@ -314,6 +321,12 @@
     _resetContextObjects();
   }
 
+  /// Update the cache with list of invalidated ids and clears [removedCacheIds].
+  void releaseAndClearRemovedIds() {
+    byteStore.release(removedCacheIds);
+    removedCacheIds.clear();
+  }
+
   /// The [completionLine] and [completionColumn] are zero based.
   ResolvedUnitResult resolve({
     int completionLine,
@@ -680,7 +693,8 @@
       cycle.directDependencies.forEach(loadBundle);
 
       var key = cycle.cyclePathsHash;
-      var bytes = byteStore.get(key, cycle.signature);
+      var data = byteStore.get(key, cycle.signature);
+      var bytes = data?.bytes;
 
       if (bytes == null) {
         librariesLinkedTimer.start();
@@ -732,7 +746,8 @@
 
         bytes = serializeBundle(cycle.signature, linkResult).toBuffer();
 
-        byteStore.put(key, cycle.signature, bytes);
+        data = byteStore.putGet(key, cycle.signature, bytes);
+        bytes = data.bytes;
         performance.getDataInt('bytesPut').add(bytes.length);
 
         librariesLinkedTimer.stop();
@@ -740,6 +755,7 @@
         performance.getDataInt('bytesGet').add(bytes.length);
         performance.getDataInt('libraryLoadCount').add(cycle.libraries.length);
       }
+      cycle.id = data.id;
 
       var cBundle = CiderLinkedLibraryCycle.fromBuffer(bytes);
       inputBundles.add(cBundle.bundle);
@@ -775,14 +791,18 @@
 
   /// Remove libraries represented by the [removed] files.
   /// If we need these libraries later, we will relink and reattach them.
-  void remove(List<FileState> removed) {
+  void remove(List<FileState> removed, Set<int> removedIds) {
     elementFactory.removeLibraries(
       removed.map((e) => e.uriStr).toSet(),
     );
 
     var removedSet = removed.toSet();
     loadedBundles.removeWhere((cycle) {
-      return cycle.libraries.any(removedSet.contains);
+      if (cycle.libraries.any(removedSet.contains)) {
+        removedIds.add(cycle.id);
+        return true;
+      }
+      return false;
     });
   }
 
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index ae2ec2a..03df87d 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -104,6 +104,8 @@
         );
     }
     argParser
+      ..addMultiOption('define',
+          abbr: 'D', help: 'Defines an environment variable', hide: true)
       ..addFlag(
         'disable-service-auth-codes',
         hide: !verbose,
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index fc444ae..5738c65 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -154,6 +154,7 @@
       '--no-pause-isolates-on-start',
       '--no-pause-isolates-on-exit',
       '--no-pause-isolates-on-unhandled-exceptions',
+      '-Dfoo=bar',
       p.relativeFilePath,
     ]);
     expect(
@@ -173,6 +174,7 @@
       '--no-pause-isolates-on-exit',
       '--no-pause-isolates-on-unhandled-exceptions',
       '--disable-service-auth-codes',
+      '-Dfoo=bar',
       p.relativeFilePath,
     ]);
 
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index dc92143..ee3f98e 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -180,7 +180,10 @@
       defaultsTo: 'amd')
   ..addFlag('flutter-widget-cache',
       help: 'Enable the widget cache to track changes to Widget subtypes',
-      defaultsTo: false);
+      defaultsTo: false)
+  ..addFlag('print-incremental-dependencies',
+      help: 'Print list of sources added and removed from compilation',
+      defaultsTo: true);
 
 String usage = '''
 Usage: server [options] [input.dart]
@@ -339,6 +342,7 @@
   bool incrementalSerialization;
   bool useDebuggerModuleNames;
   bool emitDebugMetadata;
+  bool _printIncrementalDependencies;
 
   CompilerOptions _compilerOptions;
   BytecodeOptions _bytecodeOptions;
@@ -406,6 +410,7 @@
     _kernelBinaryFilename = _kernelBinaryFilenameFull;
     _initializeFromDill =
         _options['initialize-from-dill'] ?? _kernelBinaryFilenameFull;
+    _printIncrementalDependencies = _options['print-incremental-dependencies'];
     final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     final Uri sdkRoot = _ensureFolderPath(options['sdk-root']);
@@ -609,6 +614,9 @@
   }
 
   void _outputDependenciesDelta(Iterable<Uri> compiledSources) async {
+    if (!_printIncrementalDependencies) {
+      return;
+    }
     Set<Uri> uris = Set<Uri>();
     for (Uri uri in compiledSources) {
       // Skip empty or corelib dependencies.
diff --git a/runtime/tools/verbose_gc_to_bmu.dart b/runtime/tools/verbose_gc_to_bmu.dart
index 9564e42..6868926 100644
--- a/runtime/tools/verbose_gc_to_bmu.dart
+++ b/runtime/tools/verbose_gc_to_bmu.dart
@@ -10,6 +10,7 @@
 // dart --verbose_gc foo.dart 2> foo.gclog
 // dart verbose_gc_to_bmu.dart < foo.gclog > foo.bmu
 // gnuplot -p -e "set yr [0:1]; set logscale x; plot 'foo.bmu' with linespoints"
+// @dart=2.9
 
 import 'dart:io';
 import 'dart:math';
diff --git a/tests/lib/js/extends_test/extends_test.dart b/tests/lib/js/extends_test/extends_test.dart
new file mode 100644
index 0000000..12f8e3f
--- /dev/null
+++ b/tests/lib/js/extends_test/extends_test.dart
@@ -0,0 +1,57 @@
+// 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 'extends_test_util.dart';
+
+void main() {
+  // Use the old way to define inheritance between JS objects.
+  eval(r"""
+    function inherits(child, parent) {
+      if (child.prototype.__proto__) {
+        child.prototype.__proto__ = parent.prototype;
+      } else {
+        function tmp() {};
+        tmp.prototype = parent.prototype;
+        child.prototype = new tmp();
+        child.prototype.constructor = child;
+      }
+    }
+    function JSClass(a) {
+      this.a = a;
+      this.getA = function() {
+        return this.a;
+      }
+      this.getAOrB = function() {
+        return this.getA();
+      }
+    }
+    function JSExtendJSClass(a, b) {
+      JSClass.call(this, a);
+      this.b = b;
+      this.getB = function() {
+        return this.b;
+      }
+      this.getAOrB = function() {
+        return this.getB();
+      }
+    }
+    inherits(JSExtendJSClass, JSClass);
+    function JSExtendAnonymousClass(a, b) {
+      this.a = a;
+      this.b = b;
+      this.getA = function() {
+        return this.a;
+      }
+      this.getB = function() {
+        return this.b;
+      }
+      this.getAOrB = function() {
+        return this.getB();
+      }
+    }
+    self.anonExtendAnon = new JSExtendAnonymousClass(1, 2);
+    self.anonExtendJS = new JSExtendJSClass(1, 2);
+  """);
+  testInheritance();
+}
diff --git a/tests/lib/js/extends_test/extends_test_util.dart b/tests/lib/js/extends_test/extends_test_util.dart
new file mode 100644
index 0000000..5185176
--- /dev/null
+++ b/tests/lib/js/extends_test/extends_test_util.dart
@@ -0,0 +1,94 @@
+// 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.
+
+// Tests inheritance relationships between `JS` and `anonymous` classes/objects.
+
+@JS()
+library extends_test;
+
+import 'package:expect/minitest.dart';
+import 'package:js/js.dart';
+
+@JS()
+external void eval(String code);
+
+@JS()
+class JSClass {
+  external int get a;
+  external int getA();
+  external int getAOrB();
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+  external int get a;
+  external int getA();
+}
+
+@JS()
+class JSExtendJSClass extends JSClass {
+  external JSExtendJSClass(int a, int b);
+  external int get b;
+  external int getB();
+  external int getAOrB();
+}
+
+@JS()
+class JSExtendAnonymousClass extends AnonymousClass {
+  external JSExtendAnonymousClass(int a, int b);
+  external int get b;
+  external int getB();
+}
+
+@JS()
+@anonymous
+class AnonymousExtendAnonymousClass extends AnonymousClass {
+  external int get b;
+  external int getB();
+}
+
+@JS()
+@anonymous
+class AnonymousExtendJSClass extends JSClass {
+  external int get b;
+  external int getB();
+  external int getAOrB();
+}
+
+external AnonymousExtendAnonymousClass get anonExtendAnon;
+external AnonymousExtendJSClass get anonExtendJS;
+
+void testInheritance() {
+  // Note that for the following, there are no meaningful tests for is checks or
+  // as casts, since the web compilers should return true and succeed for all JS
+  // types.
+
+  var jsExtendJS = JSExtendJSClass(1, 2);
+  expect(jsExtendJS.a, 1);
+  expect(jsExtendJS.b, 2);
+  expect(jsExtendJS.getA(), 1);
+  expect(jsExtendJS.getB(), 2);
+  // Test method overrides.
+  expect(jsExtendJS.getAOrB(), 2);
+  expect((jsExtendJS as JSClass).getAOrB(), 2);
+
+  var jsExtendAnon = JSExtendAnonymousClass(1, 2);
+  expect(jsExtendAnon.a, 1);
+  expect(jsExtendAnon.b, 2);
+  expect(jsExtendAnon.getA(), 1);
+  expect(jsExtendAnon.getB(), 2);
+
+  expect(anonExtendAnon.a, 1);
+  expect(anonExtendAnon.b, 2);
+  expect(anonExtendAnon.getA(), 1);
+  expect(anonExtendAnon.getB(), 2);
+
+  expect(anonExtendJS.a, 1);
+  expect(anonExtendJS.b, 2);
+  expect(anonExtendJS.getA(), 1);
+  expect(anonExtendJS.getB(), 2);
+  expect(anonExtendJS.getAOrB(), 2);
+  expect((anonExtendJS as JSClass).getAOrB(), 2);
+}
diff --git a/tests/lib/js/extends_test/extends_with_es6_test.dart b/tests/lib/js/extends_test/extends_with_es6_test.dart
new file mode 100644
index 0000000..00eb41f
--- /dev/null
+++ b/tests/lib/js/extends_test/extends_with_es6_test.dart
@@ -0,0 +1,54 @@
+// 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 'extends_test_util.dart';
+
+void main() {
+  // Use the ES6 syntax for classes to make inheritance easier.
+  eval(r"""
+    class JSClass {
+      constructor(a) {
+        this.a = a;
+      }
+      getA() {
+        return this.a;
+      }
+      getAOrB() {
+        return this.getA();
+      }
+    }
+    class JSExtendJSClass extends JSClass {
+      constructor(a, b) {
+        super(a);
+        this.b = b;
+      }
+      getB() {
+        return this.b;
+      }
+      getAOrB() {
+        return this.getB();
+      }
+    }
+    self.JSExtendJSClass = JSExtendJSClass;
+    class JSExtendAnonymousClass {
+      constructor(a, b) {
+        this.a = a;
+        this.b = b;
+      }
+      getA() {
+        return this.a;
+      }
+      getB() {
+        return this.b;
+      }
+      getAOrB() {
+        return this.getB();
+      }
+    }
+    self.JSExtendAnonymousClass = JSExtendAnonymousClass;
+    self.anonExtendAnon = new JSExtendAnonymousClass(1, 2);
+    self.anonExtendJS = new JSExtendJSClass(1, 2);
+  """);
+  testInheritance();
+}
diff --git a/tools/VERSION b/tools/VERSION
index 70adc94..07cb50e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 225
+PRERELEASE 226
 PRERELEASE_PATCH 0
\ No newline at end of file