Version 2.18.0-147.0.dev

Merge commit '1c27154f41827e1155d948c9dda67ecc39e79655' into 'dev'
diff --git a/pkg/analysis_server/lib/src/cider/rename.dart b/pkg/analysis_server/lib/src/cider/rename.dart
index a7ce3f3..02902f3 100644
--- a/pkg/analysis_server/lib/src/cider/rename.dart
+++ b/pkg/analysis_server/lib/src/cider/rename.dart
@@ -53,6 +53,8 @@
     } else if (element is ConstructorElement) {
       status = validateConstructorName(name);
       _analyzePossibleConflicts(element, status, name);
+    } else if (element is ImportElement) {
+      status = validateImportPrefixName(name);
     }
 
     if (status == null) {
@@ -125,34 +127,9 @@
     for (var element in elements) {
       matches.addAll(await fileResolver.findReferences2(element));
     }
-
     FlutterWidgetRename? flutterRename;
-    var flutterState = canRename._flutterWidgetState;
-    if (flutterState != null) {
-      var stateClass = flutterState.state;
-      var stateName = flutterState.newName;
-      var match = await fileResolver.findReferences2(stateClass);
-      var sourcePath = stateClass.source.fullName;
-      var location = stateClass.enclosingElement.lineInfo
-          .getLocation(stateClass.nameOffset);
-      CiderSearchMatch ciderMatch;
-      var searchInfo = CiderSearchInfo(
-          location, stateClass.nameLength, MatchKind.DECLARATION);
-      try {
-        ciderMatch = match.firstWhere((m) => m.path == sourcePath);
-        ciderMatch.references.add(searchInfo);
-      } catch (_) {
-        match.add(CiderSearchMatch(sourcePath, [], [searchInfo]));
-      }
-      var replacements = match
-          .map((m) => CiderReplaceMatch(
-              m.path,
-              m.references
-                  .map((p) => ReplaceInfo(
-                      stateName, p.startPosition, stateClass.nameLength))
-                  .toList()))
-          .toList();
-      flutterRename = FlutterWidgetRename(stateName, match, replacements);
+    if (canRename._flutterWidgetState != null) {
+      flutterRename = await _computeFlutterStateName();
     }
     var replaceMatches = <CiderReplaceMatch>[];
     if (element is ConstructorElement) {
@@ -179,6 +156,30 @@
           replaceMatches.addMatch(result.path, result.matches.toList());
         }
       }
+    } else if (element is ImportElement) {
+      var replaceInfo = <ReplaceInfo>[];
+      for (var match in matches) {
+        for (var ref in match.references) {
+          if (newName.isEmpty) {
+            replaceInfo.add(ReplaceInfo('', ref.startPosition, ref.length));
+          } else {
+            var identifier = await _getInterpolationIdentifier(
+                match.path, ref.startPosition);
+            if (identifier != null) {
+              var lineInfo = canRename.lineInfo;
+              replaceInfo.add(ReplaceInfo('{$newName.${identifier.name}}',
+                  lineInfo.getLocation(identifier.offset), identifier.length));
+            } else {
+              replaceInfo
+                  .add(ReplaceInfo('$newName.', ref.startPosition, ref.length));
+            }
+          }
+        }
+        replaceMatches.addMatch(match.path, replaceInfo);
+        var sourcePath = element.source.fullName;
+        var infos = await _addElementDeclaration(element, sourcePath);
+        replaceMatches.addMatch(sourcePath, infos);
+      }
     } else {
       for (var match in matches) {
         replaceMatches.addMatch(
@@ -213,6 +214,32 @@
             lineInfo.getLocation(element.setter!.nameOffset),
             element.setter!.nameLength));
       }
+    } else if (element is ImportElement) {
+      var prefix = element.prefix;
+      var unit =
+          (await canRename._fileResolver.resolve2(path: sourcePath)).unit;
+      var index = element.library.imports.indexOf(element);
+      var node = unit.directives.whereType<ImportDirective>().elementAt(index);
+      if (newName.isEmpty) {
+        // We should not get `prefix == null` because we check in
+        // `checkNewName` that the new name is different.
+        if (prefix == null) {
+          return infos;
+        }
+        var prefixEnd = prefix.nameOffset + prefix.nameLength;
+        infos.add(ReplaceInfo(newName, lineInfo.getLocation(node.uri.end),
+            prefixEnd - node.uri.end));
+      } else {
+        if (prefix == null) {
+          var uriEnd = node.uri.end;
+          infos.add(
+              ReplaceInfo(' as $newName', lineInfo.getLocation(uriEnd), 0));
+        } else {
+          var offset = prefix.nameOffset;
+          var length = prefix.nameLength;
+          infos.add(ReplaceInfo(newName, lineInfo.getLocation(offset), length));
+        }
+      }
     } else {
       var location = (await canRename._fileResolver.resolve2(path: sourcePath))
           .lineInfo
@@ -222,6 +249,53 @@
     return infos;
   }
 
+  Future<FlutterWidgetRename?> _computeFlutterStateName() async {
+    var flutterState = canRename._flutterWidgetState;
+    var stateClass = flutterState!.state;
+    var stateName = flutterState.newName;
+    var match = await canRename._fileResolver.findReferences2(stateClass);
+    var sourcePath = stateClass.source.fullName;
+    var location =
+        stateClass.enclosingElement.lineInfo.getLocation(stateClass.nameOffset);
+    CiderSearchMatch ciderMatch;
+    var searchInfo =
+        CiderSearchInfo(location, stateClass.nameLength, MatchKind.DECLARATION);
+    try {
+      ciderMatch = match.firstWhere((m) => m.path == sourcePath);
+      ciderMatch.references.add(searchInfo);
+    } catch (_) {
+      match.add(CiderSearchMatch(sourcePath, [searchInfo]));
+    }
+    var replacements = match
+        .map((m) => CiderReplaceMatch(
+            m.path,
+            m.references
+                .map((p) => ReplaceInfo(
+                    stateName, p.startPosition, stateClass.nameLength))
+                .toList()))
+        .toList();
+    return FlutterWidgetRename(stateName, match, replacements);
+  }
+
+  /// If the given [reference] is before an interpolated [SimpleIdentifier] in
+  /// an [InterpolationExpression] without surrounding curly brackets, return
+  /// it. Otherwise return `null`.
+  Future<SimpleIdentifier?> _getInterpolationIdentifier(
+      String path, CharacterLocation loc) async {
+    var resolvedUnit = await canRename._fileResolver.resolve2(path: path);
+    var lineInfo = resolvedUnit.lineInfo;
+    var node = NodeLocator(
+            lineInfo.getOffsetOfLine(loc.lineNumber - 1) + loc.columnNumber)
+        .searchWithin(resolvedUnit.unit);
+    if (node is SimpleIdentifier) {
+      var parent = node.parent;
+      if (parent is InterpolationExpression && parent.rightBracket == null) {
+        return node;
+      }
+    }
+    return null;
+  }
+
   Future<CiderReplaceMatch?> _replaceSyntheticConstructor() async {
     var element = canRename.refactoringElement.element;
     var classElement = element.enclosingElement;
@@ -313,6 +387,9 @@
     if (element is ConstructorElement) {
       return true;
     }
+    if (element is ImportElement) {
+      return true;
+    }
     if (element is LabelElement || element is LocalElement) {
       return true;
     }
diff --git a/pkg/analysis_server/test/src/cider/rename_test.dart b/pkg/analysis_server/test/src/cider/rename_test.dart
index 86347e6..270b014 100644
--- a/pkg/analysis_server/test/src/cider/rename_test.dart
+++ b/pkg/analysis_server/test/src/cider/rename_test.dart
@@ -651,6 +651,131 @@
         [ReplaceInfo('bar', CharacterLocation(1, 1), 3)]);
   }
 
+  void test_rename_import() async {
+    var testCode = '''
+import 'dart:async';
+^import 'dart:math' show Random, min hide max;
+void f() {
+  Future f;
+  Random r;
+  min(1, 2);
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+import 'dart:async';
+import 'dart:math' as newName show Random, min hide max;
+void f() {
+  Future f;
+  newName.Random r;
+  newName.min(1, 2);
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_import_hasCurlyBrackets() async {
+    var testCode = r'''
+// test
+^import 'dart:async';
+void f() {
+  Future f;
+  print('Future type: ${Future}');
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult(r'''
+// test
+import 'dart:async' as newName;
+void f() {
+  newName.Future f;
+  print('Future type: ${newName.Future}');
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_import_noCurlyBrackets() async {
+    var testCode = r'''
+// test
+^import 'dart:async';
+void f() {
+  Future f;
+  print('Future type: $Future');
+}
+''';
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult(r'''
+// test
+import 'dart:async' as newName;
+void f() {
+  newName.Future f;
+  print('Future type: ${newName.Future}');
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_import_onPrefixElement() async {
+    var testCode = '''
+import 'dart:async' as test;
+import 'dart:math' as test;
+void f() {
+  test.Future f;
+  ^test.pi;
+  test.e;
+}
+''';
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+import 'dart:async' as test;
+import 'dart:math' as newName;
+void f() {
+  test.Future f;
+  newName.pi;
+  newName.e;
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_import_prefix() async {
+    var testCode = '''
+import 'dart:math' as test;
+^import 'dart:async' as test;
+void f() {
+  test.max(1, 2);
+  test.Future f;
+}
+''';
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+import 'dart:math' as test;
+import 'dart:async' as newName;
+void f() {
+  test.max(1, 2);
+  newName.Future f;
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_import_remove_prefix() async {
+    var testCode = '''
+import 'dart:math' as test;
+^import 'dart:async' as test;
+void f() {
+  test.Future f;
+}
+''';
+
+    var result = await _rename(testCode, '');
+    _assertTestChangeResult('''
+import 'dart:math' as test;
+import 'dart:async';
+void f() {
+  Future f;
+}
+''', result!.replaceMatches.first.matches);
+  }
+
   void test_rename_local() async {
     var testCode = '''
 void foo() {
diff --git a/pkg/analysis_server/tool/code_completion/corpus.dart b/pkg/analysis_server/tool/code_completion/corpus.dart
index 26cae4f..db20d1b 100644
--- a/pkg/analysis_server/tool/code_completion/corpus.dart
+++ b/pkg/analysis_server/tool/code_completion/corpus.dart
@@ -6,8 +6,6 @@
 import 'dart:io';
 
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
-import 'package:html/parser.dart' show parse;
-import 'package:http/http.dart' as http;
 import 'package:path/path.dart' as path;
 
 /// Generate or update corpus data.
@@ -63,7 +61,6 @@
 
 final _appDir =
     path.join(_homeDir, 'completion_metrics', 'third_party', 'apps');
-final _client = http.Client();
 
 final _homeDir = Platform.isWindows
     ? Platform.environment['LOCALAPPDATA']!
@@ -90,12 +87,6 @@
   return CloneResult(result.exitCode, cloneDir, msg: result.stderr as String);
 }
 
-Future<String> _getBody(String url) async => (await _getResponse(url)).body;
-
-Future<http.Response> _getResponse(String url) async =>
-    _client.get(Uri.parse(url),
-        headers: const {'User-Agent': 'dart.pkg.completion_metrics'});
-
 bool _hasPubspec(FileSystemEntity f) =>
     f is Directory &&
     File(path.join(f.path, file_paths.pubspecYaml)).existsSync();
@@ -130,38 +121,3 @@
   final String msg;
   CloneResult(this.exitCode, this.directory, {this.msg = ''});
 }
-
-class RepoList {
-  static const itsallwidgetsRssFeed = 'https://itsallwidgets.com/app/feed';
-
-  // (Re) generate the list of github repos on itsallwidgets.com
-  static Future<List<String>> fromItsAllWidgetsRssFeed() async {
-    final repos = <String>{};
-
-    final body = await _getBody(itsallwidgetsRssFeed);
-    final doc = parse(body);
-    final entries = doc.querySelectorAll('entry');
-    for (var entry in entries) {
-      final link = entry.querySelector('link');
-      if (link == null) {
-        continue;
-      }
-      final href = link.attributes['href'];
-      if (href == null) {
-        continue;
-      }
-      final body = await _getBody(href);
-      final doc = parse(body);
-      final links = doc.querySelectorAll('a');
-      for (var link in links) {
-        final href = link.attributes['href'];
-        if (href != null && href.startsWith('https://github.com/')) {
-          print(href);
-          repos.add(href);
-          continue;
-        }
-      }
-    }
-    return repos.toList();
-  }
-}
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index 044b599..c27bf2a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -126,6 +126,69 @@
   VARIABLE
 }
 
+/// Visitor that adds [SearchResult]s for references to the [importElement].
+class ImportElementReferencesVisitor extends RecursiveAstVisitor<void> {
+  final List<SearchResult> results = <SearchResult>[];
+
+  final ImportElement importElement;
+  final CompilationUnitElement enclosingUnitElement;
+
+  late final Set<Element> importedElements;
+
+  ImportElementReferencesVisitor(
+      ImportElement element, this.enclosingUnitElement)
+      : importElement = element {
+    importedElements = element.namespace.definedNames.values.toSet();
+  }
+
+  @override
+  void visitExportDirective(ExportDirective node) {}
+
+  @override
+  void visitImportDirective(ImportDirective node) {}
+
+  @override
+  void visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.inDeclarationContext()) {
+      return;
+    }
+    if (importElement.prefix != null) {
+      if (node.staticElement == importElement.prefix) {
+        var parent = node.parent;
+        if (parent is PrefixedIdentifier && parent.prefix == node) {
+          var element = parent.writeOrReadElement?.declaration;
+          if (importedElements.contains(element)) {
+            _addResultForPrefix(node, parent.identifier);
+          }
+        }
+        if (parent is MethodInvocation && parent.target == node) {
+          var element = parent.methodName.staticElement?.declaration;
+          if (importedElements.contains(element)) {
+            _addResultForPrefix(node, parent.methodName);
+          }
+        }
+      }
+    } else {
+      var element = node.writeOrReadElement?.declaration;
+      if (importedElements.contains(element)) {
+        _addResult(node.offset, 0);
+      }
+    }
+  }
+
+  void _addResult(int offset, int length) {
+    Element enclosingElement =
+        _getEnclosingElement(enclosingUnitElement, offset);
+    results.add(SearchResult._(enclosingElement, SearchResultKind.REFERENCE,
+        offset, length, true, false));
+  }
+
+  void _addResultForPrefix(SimpleIdentifier prefixNode, AstNode nextNode) {
+    int prefixOffset = prefixNode.offset;
+    _addResult(prefixOffset, nextNode.offset - prefixOffset);
+  }
+}
+
 /// Search support for an [AnalysisDriver].
 class Search {
   final AnalysisDriver _driver;
@@ -503,7 +566,7 @@
       String unitPath = unitElement.source.fullName;
       var unitResult = await _driver.getResult(unitPath);
       if (unitResult is ResolvedUnitResult) {
-        var visitor = _ImportElementReferencesVisitor(element, unitElement);
+        var visitor = ImportElementReferencesVisitor(element, unitElement);
         unitResult.unit.accept(visitor);
         results.addAll(visitor.results);
       }
@@ -966,69 +1029,6 @@
   }
 }
 
-/// Visitor that adds [SearchResult]s for references to the [importElement].
-class _ImportElementReferencesVisitor extends RecursiveAstVisitor<void> {
-  final List<SearchResult> results = <SearchResult>[];
-
-  final ImportElement importElement;
-  final CompilationUnitElement enclosingUnitElement;
-
-  late final Set<Element> importedElements;
-
-  _ImportElementReferencesVisitor(
-      ImportElement element, this.enclosingUnitElement)
-      : importElement = element {
-    importedElements = element.namespace.definedNames.values.toSet();
-  }
-
-  @override
-  void visitExportDirective(ExportDirective node) {}
-
-  @override
-  void visitImportDirective(ImportDirective node) {}
-
-  @override
-  void visitSimpleIdentifier(SimpleIdentifier node) {
-    if (node.inDeclarationContext()) {
-      return;
-    }
-    if (importElement.prefix != null) {
-      if (node.staticElement == importElement.prefix) {
-        var parent = node.parent;
-        if (parent is PrefixedIdentifier && parent.prefix == node) {
-          var element = parent.writeOrReadElement?.declaration;
-          if (importedElements.contains(element)) {
-            _addResultForPrefix(node, parent.identifier);
-          }
-        }
-        if (parent is MethodInvocation && parent.target == node) {
-          var element = parent.methodName.staticElement?.declaration;
-          if (importedElements.contains(element)) {
-            _addResultForPrefix(node, parent.methodName);
-          }
-        }
-      }
-    } else {
-      var element = node.writeOrReadElement?.declaration;
-      if (importedElements.contains(element)) {
-        _addResult(node.offset, 0);
-      }
-    }
-  }
-
-  void _addResult(int offset, int length) {
-    Element enclosingElement =
-        _getEnclosingElement(enclosingUnitElement, offset);
-    results.add(SearchResult._(enclosingElement, SearchResultKind.REFERENCE,
-        offset, length, true, false));
-  }
-
-  void _addResultForPrefix(SimpleIdentifier prefixNode, AstNode nextNode) {
-    int prefixOffset = prefixNode.offset;
-    _addResult(prefixOffset, nextNode.offset - prefixOffset);
-  }
-}
-
 class _IndexRequest {
   final AnalysisDriverUnitIndex index;
 
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 592bb38..198bb5b 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/dart/analysis/feature_set_provider.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
+import 'package:analyzer/src/dart/analysis/search.dart';
 import 'package:analyzer/src/dart/micro/analysis_context.dart';
 import 'package:analyzer/src/dart/micro/cider_byte_store.dart';
 import 'package:analyzer/src/dart/micro/library_analyzer.dart';
@@ -61,26 +62,20 @@
 
 class CiderSearchMatch {
   final String path;
-  @deprecated
-  final List<CharacterLocation?> startPositions;
   final List<CiderSearchInfo> references;
 
-  CiderSearchMatch(this.path, this.startPositions, this.references);
+  CiderSearchMatch(this.path, this.references);
 
   @override
   bool operator ==(Object other) =>
       other is CiderSearchMatch &&
       path == other.path &&
-      const ListEquality<CharacterLocation?>()
-          // ignore: deprecated_member_use_from_same_package
-          .equals(startPositions, other.startPositions) &&
       const ListEquality<CiderSearchInfo>()
           .equals(references, other.references);
 
   @override
   String toString() {
-    // ignore: deprecated_member_use_from_same_package
-    return '($path, $startPositions)';
+    return '($path, $references)';
   }
 }
 
@@ -218,9 +213,6 @@
             references.add(CiderSearchMatch(
                 path,
                 matches
-                    .map((match) => lineInfo.getLocation(match.offset))
-                    .toList(),
-                matches
                     .map((match) => CiderSearchInfo(
                         lineInfo.getLocation(match.offset),
                         match.length,
@@ -235,6 +227,8 @@
       if (element is LocalVariableElement ||
           (element is ParameterElement && !element.isNamed)) {
         await collectReferences2(element.source!.fullName, performance!);
+      } else if (element is ImportElement) {
+        return await _searchReferences_Import(element);
       } else {
         var result = performance!.run('getFilesContaining', (performance) {
           return fsState!.getFilesContaining(element.displayName);
@@ -769,6 +763,27 @@
     }
   }
 
+  Future<List<CiderSearchMatch>> _searchReferences_Import(
+      ImportElement element) async {
+    var results = <CiderSearchMatch>[];
+    LibraryElement libraryElement = element.library;
+    for (CompilationUnitElement unitElement in libraryElement.units) {
+      String unitPath = unitElement.source.fullName;
+      var unitResult = await resolve2(path: unitPath);
+      var visitor = ImportElementReferencesVisitor(element, unitElement);
+      unitResult.unit.accept(visitor);
+      var lineInfo = unitResult.lineInfo;
+      var infos = visitor.results
+          .map((searchResult) => CiderSearchInfo(
+              lineInfo.getLocation(searchResult.offset),
+              searchResult.length,
+              MatchKind.REFERENCE))
+          .toList();
+      results.add(CiderSearchMatch(unitPath, infos));
+    }
+    return results;
+  }
+
   void _throwIfNotAbsoluteNormalizedPath(String path) {
     var pathContext = resourceProvider.pathContext;
     if (pathContext.normalize(path) != path) {
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 934b7bd..ffc3b74 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -396,7 +396,7 @@
     var element = await _findElement(6, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(4, 11)],
+      CiderSearchMatch(bPath,
           [CiderSearchInfo(CharacterLocation(4, 11), 1, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
@@ -418,8 +418,8 @@
     var element = await _findElement(16, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(aPath, [CharacterLocation(5, 5)],
-          [CiderSearchInfo(CharacterLocation(5, 5), 3, MatchKind.WRITE)])
+      CiderSearchMatch(
+          aPath, [CiderSearchInfo(CharacterLocation(5, 5), 3, MatchKind.WRITE)])
     ];
     expect(result, expected);
   }
@@ -438,7 +438,7 @@
     var element = await _findElement(11, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(aPath, [CharacterLocation(2, 3)],
+      CiderSearchMatch(aPath,
           [CiderSearchInfo(CharacterLocation(2, 3), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
@@ -465,7 +465,7 @@
     var element = await _findElement(20, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(5, 15)],
+      CiderSearchMatch(bPath,
           [CiderSearchInfo(CharacterLocation(5, 15), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
@@ -485,7 +485,7 @@
     var element = await _findElement(39, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(aPath, [CharacterLocation(4, 11)],
+      CiderSearchMatch(aPath,
           [CiderSearchInfo(CharacterLocation(4, 11), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
@@ -519,9 +519,9 @@
     var element = await _findElement(17, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(5, 5)],
+      CiderSearchMatch(bPath,
           [CiderSearchInfo(CharacterLocation(5, 5), 4, MatchKind.REFERENCE)]),
-      CiderSearchMatch(aPath, [CharacterLocation(7, 4)],
+      CiderSearchMatch(aPath,
           [CiderSearchInfo(CharacterLocation(7, 4), 4, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
@@ -548,8 +548,8 @@
     var element = await _findElement(21, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(5, 5)],
-          [CiderSearchInfo(CharacterLocation(5, 5), 5, MatchKind.WRITE)])
+      CiderSearchMatch(
+          bPath, [CiderSearchInfo(CharacterLocation(5, 5), 5, MatchKind.WRITE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -576,7 +576,7 @@
     var element = await _findElement(19, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(4, 13)],
+      CiderSearchMatch(bPath,
           [CiderSearchInfo(CharacterLocation(4, 13), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
@@ -604,7 +604,7 @@
     var element = await _findElement(20, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(4, 3)],
+      CiderSearchMatch(bPath,
           [CiderSearchInfo(CharacterLocation(4, 3), 3, MatchKind.WRITE)]),
     ];
     expect(result, unorderedEquals(expected));
@@ -625,8 +625,8 @@
     var element = await _findElement(10, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(aPath, [CharacterLocation(4, 11)],
-          [CiderSearchInfo(CharacterLocation(4, 11), 1, MatchKind.READ)])
+      CiderSearchMatch(
+          aPath, [CiderSearchInfo(CharacterLocation(4, 11), 1, MatchKind.READ)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -645,21 +645,11 @@
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(aPath, [
-        CharacterLocation(2, 8),
-        CharacterLocation(4, 12)
-      ], [
-        CiderSearchInfo(CharacterLocation(2, 8), 5, MatchKind.WRITE),
-        CiderSearchInfo(CharacterLocation(4, 12), 5, MatchKind.WRITE)
+        CiderSearchInfo(CharacterLocation(2, 8), 1, MatchKind.REFERENCE),
+        CiderSearchInfo(CharacterLocation(4, 12), 1, MatchKind.REFERENCE)
       ])
     ];
-    expect(result.map((e) => e.path),
-        unorderedEquals(expected.map((e) => e.path)));
-    // ignore: deprecated_member_use_from_same_package
-    expect(
-        // ignore: deprecated_member_use_from_same_package
-        result.map((e) => e.startPositions),
-        // ignore: deprecated_member_use_from_same_package
-        unorderedEquals(expected.map((e) => e.startPositions)));
+    expect(result, expected);
   }
 
   test_findReferences_typedef() async {
@@ -679,7 +669,7 @@
     var element = await _findElement(8, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(3, 8)],
+      CiderSearchMatch(bPath,
           [CiderSearchInfo(CharacterLocation(3, 8), 4, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
diff --git a/pkg/compiler/lib/src/common/elements.dart b/pkg/compiler/lib/src/common/elements.dart
index a66fe73..47d4930 100644
--- a/pkg/compiler/lib/src/common/elements.dart
+++ b/pkg/compiler/lib/src/common/elements.dart
@@ -915,7 +915,7 @@
   // From dart:_js_embedded_names
 
   late final ClassEntity jsGetNameEnum = _findClass(
-      _env.lookupLibrary(Uris.dart__js_embedded_names, required: true),
+      _env.lookupLibrary(Uris.dart__js_shared_embedded_names, required: true),
       'JsGetName')!;
 
   /// Returns `true` if [member] is a "foreign helper", that is, a member whose
@@ -1185,7 +1185,7 @@
       'NativeTypedArrayOfDouble')!;
 
   late final ClassEntity jsBuiltinEnum = _findClass(
-      _env.lookupLibrary(Uris.dart__js_embedded_names, required: true),
+      _env.lookupLibrary(Uris.dart__js_shared_embedded_names, required: true),
       'JsBuiltin')!;
 
   bool isForeign(MemberEntity element) => element.library == foreignLibrary;
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 024be8a..3058b11 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -249,6 +249,10 @@
   static final Uri dart__js_embedded_names =
       Uri(scheme: 'dart', path: '_js_embedded_names');
 
+  /// The URI for 'dart:_js_shared_embedded_names'.
+  static final Uri dart__js_shared_embedded_names =
+      Uri(scheme: 'dart', path: '_js_shared_embedded_names');
+
   /// The URI for 'dart:js'.
   static final Uri dart_js = Uri(scheme: 'dart', path: 'js');
 
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index e84fc46..a1b132b 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -24,6 +24,7 @@
 import 'deferred_load/output_unit.dart' show OutputUnit, deferredPartFileName;
 import 'dump_info_javascript_monitor.dart';
 import 'elements/entities.dart';
+import 'elements/entity_utils.dart' as entity_utils;
 import 'inferrer/abstract_value_domain.dart';
 import 'inferrer/types.dart'
     show GlobalTypeInferenceMemberResult, GlobalTypeInferenceResults;
@@ -663,14 +664,16 @@
     List<ClosureInfo> nestedClosures = <ClosureInfo>[];
     localFunctionInfoCollector.localFunctions.forEach((key, value) {
       FunctionEntity closureEntity;
+      int closureOrder = value.order;
       environment.forEachNestedClosure(memberEntity, (closure) {
-        if (closure.enclosingClass.name == value.name) {
+        if (closure.enclosingClass.name == value.name &&
+            (closureOrder-- == 0)) {
           closureEntity = closure;
         }
       });
       final closureClassEntity = closureEntity.enclosingClass;
-      final closureInfo =
-          ClosureInfo(name: value.name, outputUnit: null, size: null);
+      final closureInfo = ClosureInfo(
+          name: value.disambiguatedName, outputUnit: null, size: null);
       state.entityToInfo[closureClassEntity] = closureInfo;
 
       FunctionEntity callMethod = closedWorld.elementEnvironment
@@ -691,6 +694,32 @@
   }
 }
 
+/// Maps JWorld Entity objects to disambiguated names in order to map them
+/// to/from Kernel.
+///
+/// This is primarily used for naming closure objects, which rely on Entity
+/// object identity to determine uniqueness.
+///
+/// Note: this relies on the Kernel traversal order to determine order, which
+/// may change in the future.
+class EntityDisambiguator {
+  final nameFrequencies = <String, int>{};
+  final entityNames = <Entity, String>{};
+
+  String name(Entity entity) {
+    final disambiguatedName = entityNames[entity];
+    if (disambiguatedName != null) {
+      return disambiguatedName;
+    }
+    nameFrequencies[entity.name] = (nameFrequencies[entity.name] ?? -1) + 1;
+    final order = nameFrequencies[entity.name];
+    entityNames[entity] =
+        order == 0 ? entity.name : '${entity.name}%${order - 1}';
+
+    return entityNames[entity];
+  }
+}
+
 /// Annotates [KernelInfoCollector] with info extracted from closed-world
 /// analysis.
 class DumpInfoAnnotator {
@@ -699,6 +728,7 @@
   final JClosedWorld closedWorld;
   final GlobalTypeInferenceResults _globalInferenceResults;
   final DumpInfoTask dumpInfoTask;
+  final entityDisambiguator = EntityDisambiguator();
 
   JElementEnvironment get environment => closedWorld.elementEnvironment;
 
@@ -901,8 +931,9 @@
   }
 
   ClosureInfo visitClosureClass(ClassEntity element) {
+    final disambiguatedElementName = entityDisambiguator.name(element);
     final kClosureInfos = kernelInfo.state.info.closures
-        .where((info) => info.name == element.name)
+        .where((info) => info.name == disambiguatedElementName)
         .toList();
     assert(
         kClosureInfos.length == 1,
@@ -916,7 +947,8 @@
     FunctionEntity callMethod = closedWorld.elementEnvironment
         .lookupClassMember(element, Identifiers.call);
 
-    visitFunction(callMethod, element.name);
+    final functionInfo = visitFunction(callMethod, disambiguatedElementName);
+    if (functionInfo == null) return null;
 
     kClosureInfo.treeShakenStatus = TreeShakenStatus.Live;
     return kClosureInfo;
@@ -926,8 +958,8 @@
   // not always be valid. Check and validate later.
   FunctionInfo visitFunction(FunctionEntity function, String parentName) {
     int size = dumpInfoTask.sizeOf(function);
-    // TODO(sigmund): consider adding a small info to represent unreachable
-    // code here.
+    if (size == 0 && !shouldKeep(function)) return null;
+
     var compareName = function.name;
     if (function.isConstructor) {
       compareName = compareName == ""
@@ -1477,63 +1509,36 @@
 
 class LocalFunctionInfo {
   final ir.LocalFunction localFunction;
-  final List<ir.TreeNode> hierarchy;
   final String name;
+  final int order;
   bool isInvoked = false;
 
-  LocalFunctionInfo._(this.localFunction, this.hierarchy, this.name);
+  LocalFunctionInfo(this.localFunction, this.name, this.order);
 
-  factory LocalFunctionInfo(ir.LocalFunction localFunction) {
-    String name = '';
-    ir.TreeNode node = localFunction;
-    final hierarchy = <ir.TreeNode>[];
-    bool inClosure = false;
-    while (node != null) {
-      // Only consider nodes used for resolving a closure's full name.
-      if (node is ir.FunctionDeclaration) {
-        hierarchy.add(node);
-        name = '_${node.variable.name}' + name;
-        inClosure = false;
-      } else if (node is ir.FunctionExpression) {
-        hierarchy.add(node);
-        name = (inClosure ? '_' : '_closure') + name;
-        inClosure = true;
-      } else if (node is ir.Member) {
-        hierarchy.add(node);
-        var cleanName = node.toStringInternal();
-        if (cleanName.endsWith('.'))
-          cleanName = cleanName.substring(0, cleanName.length - 1);
-        final isFactory = node is ir.Procedure && node.isFactory;
-        if (isFactory) {
-          cleanName = cleanName.replaceAll('.', '\$');
-          cleanName = '${node.enclosingClass.toStringInternal()}_' + cleanName;
-        } else {
-          cleanName = cleanName.replaceAll('.', '_');
-        }
-        name = cleanName + name;
-        inClosure = false;
-      }
-      node = node.parent;
-    }
-
-    return LocalFunctionInfo._(localFunction, hierarchy, name);
-  }
+  get disambiguatedName => order == 0 ? name : '$name%${order - 1}';
 }
 
 class LocalFunctionInfoCollector extends ir.RecursiveVisitor<void> {
   final localFunctions = <ir.LocalFunction, LocalFunctionInfo>{};
+  final localFunctionNames = <String, int>{};
+
+  LocalFunctionInfo generateLocalFunctionInfo(ir.LocalFunction localFunction) {
+    final name = _computeClosureName(localFunction);
+    localFunctionNames[name] = (localFunctionNames[name] ?? -1) + 1;
+    return LocalFunctionInfo(localFunction, name, localFunctionNames[name]);
+  }
 
   @override
   void visitFunctionExpression(ir.FunctionExpression node) {
     assert(localFunctions[node] == null);
-    localFunctions[node] = LocalFunctionInfo(node);
+    localFunctions[node] = generateLocalFunctionInfo(node);
     defaultExpression(node);
   }
 
   @override
   void visitFunctionDeclaration(ir.FunctionDeclaration node) {
     assert(localFunctions[node] == null);
-    localFunctions[node] = LocalFunctionInfo(node);
+    localFunctions[node] = generateLocalFunctionInfo(node);
     defaultStatement(node);
   }
 
@@ -1544,3 +1549,57 @@
     localFunctions[node.localFunction].isInvoked = true;
   }
 }
+
+// Returns a non-unique name for the given closure element.
+//
+// Must be kept logically identical to js_model/element_map_impl.dart.
+String _computeClosureName(ir.TreeNode treeNode) {
+  String reconstructConstructorName(ir.Member node) {
+    String className = node.enclosingClass.name;
+    if (node.name.text == '') {
+      return className;
+    } else {
+      return '$className\$${node.name}';
+    }
+  }
+
+  var parts = <String>[];
+  // First anonymous is called 'closure', outer ones called '' to give a
+  // compound name where increasing nesting level corresponds to extra
+  // underscores.
+  var anonymous = 'closure';
+  ir.TreeNode current = treeNode;
+  while (current != null) {
+    var node = current;
+    if (node is ir.FunctionExpression) {
+      parts.add(anonymous);
+      anonymous = '';
+    } else if (node is ir.FunctionDeclaration) {
+      String name = node.variable.name;
+      if (name != null && name != "") {
+        parts.add(entity_utils.operatorNameToIdentifier(name));
+      } else {
+        parts.add(anonymous);
+        anonymous = '';
+      }
+    } else if (node is ir.Class) {
+      parts.add(node.name);
+      break;
+    } else if (node is ir.Procedure) {
+      if (node.kind == ir.ProcedureKind.Factory) {
+        parts.add(reconstructConstructorName(node));
+      } else {
+        parts.add(entity_utils.operatorNameToIdentifier(node.name.text));
+      }
+    } else if (node is ir.Constructor) {
+      parts.add(reconstructConstructorName(node));
+      break;
+    } else if (node is ir.Field) {
+      // Add the field name for closures in field initializers.
+      String name = node.name?.text;
+      if (name != null) parts.add(name);
+    }
+    current = current.parent;
+  }
+  return parts.reversed.join('_');
+}
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 392e4e5..dc91161 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -9,7 +9,7 @@
 import 'package:front_end/src/api_unstable/dart2js.dart'
     show $0, $9, $A, $Z, $_, $a, $g, $s, $z;
 
-import 'package:js_runtime/synced/embedded_names.dart' show JsGetName;
+import 'package:js_shared/synced/embedded_names.dart' show JsGetName;
 
 import '../closure.dart';
 import '../common.dart';
diff --git a/pkg/compiler/lib/src/js_backend/string_reference.dart b/pkg/compiler/lib/src/js_backend/string_reference.dart
index 966223b..a07a756 100644
--- a/pkg/compiler/lib/src/js_backend/string_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/string_reference.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.10
-
 /// StringReferences are 'holes' in the generated JavaScript that are filled in
 /// by the emitter with code to access a large string.
 ///
@@ -64,7 +62,7 @@
 
 import '../constants/values.dart' show StringConstantValue;
 import '../js/js.dart' as js;
-import '../serialization/serialization.dart';
+import '../serialization/serialization_interfaces.dart';
 import '../util/util.dart' show Hashing;
 import 'frequency_assignment.dart';
 import 'name_sequence.dart';
@@ -95,10 +93,10 @@
 
   final StringConstantValue constant;
 
-  js.Expression _value;
+  js.Expression? _value;
 
   @override
-  final js.JavaScriptNodeSourceInformation sourceInformation;
+  final js.JavaScriptNodeSourceInformation? sourceInformation;
 
   StringReference(this.constant) : sourceInformation = null;
   StringReference._(this.constant, this._value, this.sourceInformation);
@@ -117,14 +115,15 @@
   }
 
   set value(js.Expression value) {
-    assert(!isFinalized && value != null);
+    assert(!isFinalized);
+    assert((value as dynamic) != null); // TODO(48820): Remove when sound.
     _value = value;
   }
 
   @override
   js.Expression get value {
     assert(isFinalized, 'StringReference is unassigned');
-    return _value;
+    return _value!;
   }
 
   @override
@@ -137,14 +136,14 @@
 
   @override
   StringReference withSourceInformation(
-      js.JavaScriptNodeSourceInformation newSourceInformation) {
+      js.JavaScriptNodeSourceInformation? newSourceInformation) {
     if (newSourceInformation == sourceInformation) return this;
     if (newSourceInformation == null) return this;
     return StringReference._(constant, _value, newSourceInformation);
   }
 
   @override
-  Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
+  Iterable<js.Node> get containedNodes => isFinalized ? [_value!] : const [];
 
   @override
   String nonfinalizedDebugText() {
@@ -175,23 +174,24 @@
 /// and initializes the variable.
 class StringReferenceResource extends js.DeferredStatement
     implements js.AstContainer {
-  js.Statement _statement;
+  js.Statement? _statement;
 
   @override
-  final js.JavaScriptNodeSourceInformation sourceInformation;
+  final js.JavaScriptNodeSourceInformation? sourceInformation;
 
   StringReferenceResource() : sourceInformation = null;
   StringReferenceResource._(this._statement, this.sourceInformation);
 
   set statement(js.Statement statement) {
-    assert(!isFinalized && statement != null);
+    assert(!isFinalized);
+    assert((statement as dynamic) != null); // TODO(48820): Remove when sound.
     _statement = statement;
   }
 
   @override
   js.Statement get statement {
     assert(isFinalized, 'StringReferenceResource is unassigned');
-    return _statement;
+    return _statement!;
   }
 
   @override
@@ -199,14 +199,15 @@
 
   @override
   StringReferenceResource withSourceInformation(
-      js.JavaScriptNodeSourceInformation newSourceInformation) {
+      js.JavaScriptNodeSourceInformation? newSourceInformation) {
     if (newSourceInformation == sourceInformation) return this;
     if (newSourceInformation == null) return this;
     return StringReferenceResource._(_statement, newSourceInformation);
   }
 
   @override
-  Iterable<js.Node> get containedNodes => isFinalized ? [_statement] : const [];
+  Iterable<js.Node> get containedNodes =>
+      isFinalized ? [_statement!] : const [];
 
   @override
   void visitChildren<T>(js.NodeVisitor<T> visitor) {
@@ -233,8 +234,8 @@
   final bool _minify;
   final int shortestSharedLength; // Configurable for testing.
 
-  /*late final*/ _StringReferenceCollectorVisitor _visitor;
-  StringReferenceResource _resource;
+  late final _StringReferenceCollectorVisitor _visitor;
+  StringReferenceResource? _resource;
 
   /// Maps the recipe (type expression) to the references with the same recipe.
   /// Much of the algorithm's state is stored in the _ReferenceSet objects.
@@ -295,20 +296,20 @@
     List<js.Property> properties = [];
     for (_ReferenceSet referenceSet in referenceSetsUsingProperties) {
       String string = referenceSet.constant.stringValue;
-      var propertyName = js.string(referenceSet.propertyName);
+      var propertyName = js.string(referenceSet.propertyName!);
       properties.add(js.Property(propertyName, js.string(string)));
-      var access = js.js('#.#', [holderLocalName, propertyName]);
+      js.Expression access = js.js('#.#', [holderLocalName, propertyName]);
       for (StringReference ref in referenceSet._references) {
         ref.value = access;
       }
     }
 
     if (properties.isEmpty) {
-      _resource.statement = js.Block.empty();
+      _resource!.statement = js.Block.empty();
     } else {
       js.Expression initializer =
           js.ObjectInitializer(properties, isOneLiner: false);
-      _resource.statement = js.js.statement(
+      _resource!.statement = js.js.statement(
           r'var # = #', [js.VariableDeclaration(holderLocalName), initializer]);
     }
   }
@@ -377,7 +378,7 @@
         referencesByFrequency[index].propertyName = name;
       } else {
         var refSet = referencesByFrequency[index];
-        refSet.propertyName = name + '_' + refSet.name;
+        refSet.propertyName = name + '_' + refSet.name!;
       }
     }
 
@@ -401,10 +402,10 @@
   /// Characteristic name of the recipe - this can be used as a property name
   /// for emitting unminified code, and as a stable hash source for minified
   /// names.  [name] is `null` if [recipe] should always be generated at use.
-  String name;
+  String? name;
 
   /// Property name for 'indexing' into the precomputed types.
-  String propertyName;
+  String? propertyName;
 
   /// A stable hash code that can be used for picking stable minified names.
   int hash = 0;
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 8f32690..5da86d0 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -807,7 +807,7 @@
         resourceName,
         fragment.fragments,
         holderCode);
-    js.Expression code = js.js(_deferredBoilerplate, {
+    js.Expression /*!*/ code = js.js(_deferredBoilerplate, {
       // TODO(floitsch): don't just reference 'init'.
       'embeddedGlobalsObject': js.Parameter('init'),
       'isCollectingRuntimeMetrics': _options.experimentalTrackAllocations,
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 9ff95c5..254b4c7 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -10,7 +10,6 @@
 
 import 'package:js_runtime/synced/embedded_names.dart'
     show
-        ARRAY_RTI_PROPERTY,
         DEFERRED_INITIALIZED,
         DEFERRED_LIBRARY_PARTS,
         DEFERRED_PART_URIS,
@@ -19,18 +18,22 @@
         INTERCEPTORS_BY_TAG,
         IS_HUNK_INITIALIZED,
         IS_HUNK_LOADED,
-        JsGetName,
         LEAF_TAGS,
         MANGLED_GLOBAL_NAMES,
         MANGLED_NAMES,
         METADATA,
         NATIVE_SUPERCLASS_TAG_NAME,
-        RTI_UNIVERSE,
-        RtiUniverseFieldNames,
         RUNTIME_METRICS,
         STARTUP_METRICS,
         TearOffParametersPropertyNames,
-        TYPE_TO_INTERCEPTOR_MAP,
+        TYPE_TO_INTERCEPTOR_MAP;
+
+import 'package:js_shared/synced/embedded_names.dart'
+    show
+        ARRAY_RTI_PROPERTY,
+        JsGetName,
+        RTI_UNIVERSE,
+        RtiUniverseFieldNames,
         TYPES;
 
 import 'package:js_ast/src/precedence.dart' as js_precedence;
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index a5172df..5b51960 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -261,6 +261,7 @@
     'dart:_js_helper',
     'dart:_js_names',
     'dart:_js_primitives',
+    'dart:_js_shared_embedded_names',
     'dart:_late_helper',
     'dart:_metadata',
     'dart:_native_typed_data',
@@ -296,6 +297,7 @@
     'dart:_js_helper',
     'dart:_js_names',
     'dart:_js_primitives',
+    'dart:_js_shared_embedded_names',
     'dart:_late_helper',
     'dart:_native_typed_data',
     'dart:_recipe_syntax',
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index f28ab293..e2437be 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -6,7 +6,7 @@
 
 import 'package:front_end/src/api_prototype/constant_evaluator.dart' as ir;
 import 'package:front_end/src/api_unstable/dart2js.dart' as ir;
-import 'package:js_runtime/synced/embedded_names.dart';
+import 'package:js_shared/synced/embedded_names.dart' show JsGetName;
 import 'package:kernel/ast.dart' as ir;
 import 'package:kernel/class_hierarchy.dart' as ir;
 import 'package:kernel/core_types.dart' as ir;
diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
index 5fac8e9..2285eab 100644
--- a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
@@ -4,6 +4,7 @@
 
 import 'package:kernel/ast.dart' as ir show DartType, Member, TreeNode;
 
+import '../constants/values.dart' show ConstantValue;
 import '../elements/entities.dart';
 import '../elements/types.dart' show DartType;
 
@@ -84,6 +85,8 @@
 
   void writeList<E extends Object>(Iterable<E>? values, void f(E value),
       {bool allowNull = false});
+
+  void writeConstant(ConstantValue value);
 }
 
 /// Migrated interface for methods of DataSourceReader.
@@ -129,4 +132,6 @@
 
   List<E> readList<E extends Object>(E f());
   List<E>? readListOrNull<E extends Object>(E f());
+
+  ConstantValue readConstant();
 }
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart
index cc836b4..077bfd8 100644
--- a/pkg/compiler/lib/src/serialization/sink.dart
+++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -925,6 +925,7 @@
   }
 
   /// Writes the constant [value] to this data sink.
+  @override
   void writeConstant(ConstantValue value) {
     _writeDataKind(DataKind.constant);
     _writeConstant(value);
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index a0e4284..81e477b 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -1098,6 +1098,7 @@
   }
 
   /// Reads a constant value from this data source.
+  @override
   ConstantValue readConstant() {
     _checkDataKind(DataKind.constant);
     return _readConstant();
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index cc26197..dda60e0 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5,6 +5,8 @@
 // @dart = 2.10
 
 import 'package:js_runtime/synced/embedded_names.dart';
+import 'package:js_shared/synced/embedded_names.dart'
+    show JsBuiltin, JsGetName, TYPES;
 import 'package:kernel/ast.dart' as ir;
 
 import '../closure.dart';
diff --git a/pkg/compiler/test/dump_info/data/closures.dart b/pkg/compiler/test/dump_info/data/closures.dart
index e8b525a..997b340 100644
--- a/pkg/compiler/test/dump_info/data/closures.dart
+++ b/pkg/compiler/test/dump_info/data/closures.dart
@@ -46,10 +46,13 @@
   "id": "library/memory:sdk/tests/web/native/main.dart::",
   "kind": "library",
   "name": "<unnamed>",
-  "size": 10341,
+  "size": 12431,
   "children": [
     "class/memory:sdk/tests/web/native/main.dart::Class1",
     "function/memory:sdk/tests/web/native/main.dart::main",
+    "function/memory:sdk/tests/web/native/main.dart::nested",
+    "function/memory:sdk/tests/web/native/main.dart::nested2",
+    "function/memory:sdk/tests/web/native/main.dart::siblings",
     "function/memory:sdk/tests/web/native/main.dart::topLevelMethod1",
     "function/memory:sdk/tests/web/native/main.dart::topLevelMethod2",
     "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3",
@@ -66,7 +69,6 @@
   "imports": []
 }]
 */
-
 /*class: Class1:class=[{
   "id": "class/memory:sdk/tests/web/native/main.dart::Class1",
   "kind": "class",
@@ -1080,12 +1082,216 @@
   return local2;
 }
 
+/*member: nested:
+ closure=[
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::nested.nested_nested1",
+  "kind": "closure",
+  "name": "nested_nested1",
+  "size": 225,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::nested",
+  "function": "function/memory:sdk/tests/web/native/main.dart::nested.nested_nested1.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::nested.nested_nested1_nested2",
+  "kind": "closure",
+  "name": "nested_nested1_nested2",
+  "size": 227,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::nested",
+  "function": "function/memory:sdk/tests/web/native/main.dart::nested.nested_nested1_nested2.call"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::nested",
+  "kind": "function",
+  "name": "nested",
+  "size": 568,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::nested.nested_nested1",
+    "closure/memory:sdk/tests/web/native/main.dart::nested.nested_nested1_nested2"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[null]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "nested() {\n      var t1 = {};\n      t1.x = null;\n      new A.nested_nested1(t1).call$0();\n      t1.x.call$0();\n    }",
+  "type": "dynamic Function()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::nested.nested_nested1.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::nested.nested_nested1.call","mask":null}]
+*/
+dynamic nested() {
+  dynamic x;
+  nested1() {
+    nested2() => nested1;
+    x = nested2;
+  }
+
+  nested1();
+  x();
+}
+
+/*member: nested2:
+ closure=[
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1",
+  "kind": "closure",
+  "name": "nested2_local1",
+  "size": 195,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::nested2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1__closure",
+  "kind": "closure",
+  "name": "nested2_local1__closure",
+  "size": 193,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::nested2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1__closure.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1_closure",
+  "kind": "closure",
+  "name": "nested2_local1_closure",
+  "size": 311,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::nested2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1_closure.call"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::nested2",
+  "kind": "function",
+  "name": "nested2",
+  "size": 764,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1",
+    "closure/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1__closure",
+    "closure/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[null]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "nested2() {\n      A.print(new A.nested2_local1().call$0());\n    }",
+  "type": "dynamic Function()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/dart:core::print","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::nested2.nested2_local1.call","mask":null}]
+*/
+dynamic nested2() {
+  dynamic y;
+  int local1() {
+    return (() => 1 + (() => 2)())();
+  }
+
+  y = local1();
+  print(y);
+}
+
+/*member: siblings:
+ closure=[
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1",
+  "kind": "closure",
+  "name": "siblings_local1",
+  "size": 244,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::siblings",
+  "function": "function/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1_closure",
+  "kind": "closure",
+  "name": "siblings_local1_closure",
+  "size": 193,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::siblings",
+  "function": "function/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1_closure.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1_closure%0",
+  "kind": "closure",
+  "name": "siblings_local1_closure",
+  "size": 197,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::siblings",
+  "function": "function/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1_closure.call%0"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::siblings",
+  "kind": "function",
+  "name": "siblings",
+  "size": 701,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1",
+    "closure/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1_closure",
+    "closure/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1_closure%0"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[null]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "siblings() {\n      A.print(new A.siblings_local1().call$0());\n    }",
+  "type": "dynamic Function()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/dart:core::print","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::siblings.siblings_local1.call","mask":null}]
+*/
+dynamic siblings() {
+  int local1() {
+    int a = (() => 1)();
+    dynamic b = () => 2;
+    int c = (() => 3)();
+    return a + c;
+  }
+
+  print(local1());
+}
+
 /*member: main:
  function=[{
   "id": "function/memory:sdk/tests/web/native/main.dart::main",
   "kind": "function",
   "name": "main",
-  "size": 649,
+  "size": 706,
   "outputUnit": "outputUnit/main",
   "parent": "library/memory:sdk/tests/web/native/main.dart::",
   "children": [],
@@ -1100,7 +1306,7 @@
   "parameters": [],
   "sideEffects": "SideEffects(reads anything; writes anything)",
   "inlinedCount": 0,
-  "code": "main() {\n      var t2,\n        t1 = type$.int;\n      A.createRuntimeType(A.Class1$(t1).$ti._precomputed1);\n      A.Class1$(t1).method2$0();\n      A.Class1_Class1$fact2(t1).funcField.call$0();\n      A.Class1$(t1);\n      t2 = type$.double;\n      A.createRuntimeType(t2);\n      A.Class1$(t1).method4$1$0(t2);\n      A.Class1$(t1).method5$0();\n      A.Class1$(t1).method6$1$0(t2);\n      A.createRuntimeType(t2);\n      A.Class1_staticMethod2(t2);\n      A.Class1_staticMethod3();\n      A.Class1_staticMethod4(t2);\n      A.createRuntimeType(t2);\n      A.topLevelMethod2(t2);\n      A.topLevelMethod3();\n      A.topLevelMethod4(t2);\n      A.twoLocals();\n    }",
+  "code": "main() {\n      var t2,\n        t1 = type$.int;\n      A.createRuntimeType(A.Class1$(t1).$ti._precomputed1);\n      A.Class1$(t1).method2$0();\n      A.Class1_Class1$fact2(t1).funcField.call$0();\n      A.Class1$(t1);\n      t2 = type$.double;\n      A.createRuntimeType(t2);\n      A.Class1$(t1).method4$1$0(t2);\n      A.Class1$(t1).method5$0();\n      A.Class1$(t1).method6$1$0(t2);\n      A.createRuntimeType(t2);\n      A.Class1_staticMethod2(t2);\n      A.Class1_staticMethod3();\n      A.Class1_staticMethod4(t2);\n      A.createRuntimeType(t2);\n      A.topLevelMethod2(t2);\n      A.topLevelMethod3();\n      A.topLevelMethod4(t2);\n      A.twoLocals();\n      A.nested();\n      A.nested2();\n      A.siblings();\n    }",
   "type": "dynamic Function()"
 }],
  holding=[
@@ -1125,6 +1331,9 @@
   {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2","mask":null},
   {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3","mask":null},
   {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::nested","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::nested2","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::siblings","mask":null},
   {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod1","mask":"inlined"},
   {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod1","mask":null},
   {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod2","mask":null},
@@ -1149,4 +1358,7 @@
   topLevelMethod3();
   topLevelMethod4<double>();
   twoLocals();
+  nested();
+  nested2();
+  siblings();
 }
diff --git a/pkg/js_runtime/lib/synced/embedded_names.dart b/pkg/js_runtime/lib/synced/embedded_names.dart
index 9d48e1a..0c99f47 100644
--- a/pkg/js_runtime/lib/synced/embedded_names.dart
+++ b/pkg/js_runtime/lib/synced/embedded_names.dart
@@ -26,22 +26,12 @@
 /// the static function's unique (potentially minified) name.
 const STATIC_FUNCTION_NAME_PROPERTY_NAME = r'$static_name';
 
-/// The name of a property on the constructor function of Dart Object
-/// and interceptor types, used for caching Rti types.
-const CONSTRUCTOR_RTI_CACHE_PROPERTY_NAME = r'$ccache';
-
 /// The name of the embedded global for metadata.
 ///
 /// Use [JsBuiltin.getMetadata] instead of directly accessing this embedded
 /// global.
 const METADATA = 'metadata';
 
-/// A list of types used in the program e.g. for reflection or encoding of
-/// function types.
-///
-/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
-const TYPES = 'types';
-
 /// A JS map from mangled global names to their unmangled names.
 ///
 /// If the program does not use reflection, this embedded global may be empty
@@ -94,11 +84,6 @@
 //    [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
 const ISOLATE_TAG = 'isolateTag';
 
-/// An embedded global that contains the property used to store type information
-/// on JavaScript Array instances. This is a Symbol (except for IE11, where is
-/// is a String).
-const ARRAY_RTI_PROPERTY = 'arrayRti';
-
 /// This embedded global (a function) returns the isolate-specific dispatch-tag
 /// that is used to accelerate interceptor calls.
 const DISPATCH_PROPERTY_NAME = "dispatchPropertyName";
@@ -174,11 +159,6 @@
 /// globals don't clash with it.
 const DEFERRED_INITIALIZED = 'deferredInitialized';
 
-/// A 'Universe' object used by 'dart:_rti'.
-///
-/// This embedded global is used for --experiment-new-rti.
-const RTI_UNIVERSE = 'typeUniverse';
-
 /// An embedded global used to collect and access runtime metrics.
 const RUNTIME_METRICS = 'rm';
 
@@ -188,103 +168,6 @@
 /// An embedded global used to collect and access startup metrics.
 const STARTUP_METRICS = 'sm';
 
-/// Names that are supported by [JS_GET_NAME].
-// TODO(herhut): Make entries lower case (as in fields) and find a better name.
-enum JsGetName {
-  GETTER_PREFIX,
-  SETTER_PREFIX,
-  CALL_PREFIX,
-  CALL_PREFIX0,
-  CALL_PREFIX1,
-  CALL_PREFIX2,
-  CALL_PREFIX3,
-  CALL_PREFIX4,
-  CALL_PREFIX5,
-  CALL_CATCH_ALL,
-  REQUIRED_PARAMETER_PROPERTY,
-  DEFAULT_VALUES_PROPERTY,
-  CALL_NAME_PROPERTY,
-  DEFERRED_ACTION_PROPERTY,
-
-  /// Prefix used for generated type test property on classes.
-  OPERATOR_IS_PREFIX,
-
-  /// Name used for generated function types on classes and methods.
-  SIGNATURE_NAME,
-
-  /// Name of JavaScript property used to store runtime-type information on
-  /// instances of parameterized classes.
-  RTI_NAME,
-
-  /// String representation of the type of the Future class.
-  FUTURE_CLASS_TYPE_NAME,
-
-  /// Field name used for determining if an object or its interceptor has
-  /// JavaScript indexing behavior.
-  IS_INDEXABLE_FIELD_NAME,
-
-  /// String representation of the type of the null class.
-  NULL_CLASS_TYPE_NAME,
-
-  /// String representation of the type of the object class.
-  OBJECT_CLASS_TYPE_NAME,
-
-  /// String representation of the type of the List class.
-  LIST_CLASS_TYPE_NAME,
-
-  /// Property name for Rti._as field.
-  RTI_FIELD_AS,
-
-  /// Property name for Rti._is field.
-  RTI_FIELD_IS,
-}
-
-enum JsBuiltin {
-  /// Returns the JavaScript constructor function for Dart's Object class.
-  /// This can be used for type tests, as in
-  ///
-  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
-  ///     if (JS('bool', '# instanceof #', obj, constructor))
-  ///       ...
-  dartObjectConstructor,
-
-  /// Returns the JavaScript constructor function for the runtime's Closure
-  /// class, the base class of all closure objects.  This can be used for type
-  /// tests, as in
-  ///
-  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
-  ///     if (JS('bool', '# instanceof #', obj, constructor))
-  ///       ...
-  dartClosureConstructor,
-
-  /// Returns true if the given type is a type argument of a js-interop class
-  /// or a supertype of a js-interop class.
-  ///
-  ///     JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
-  isJsInteropTypeArgument,
-
-  /// Returns the metadata of the given [index].
-  ///
-  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
-  ///                JsBuiltin.getMetadata, index);
-  getMetadata,
-
-  /// Returns the type of the given [index].
-  ///
-  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
-  ///                JsBuiltin.getType, index);
-  getType,
-}
-
-/// Names of fields of the Rti Universe object.
-class RtiUniverseFieldNames {
-  static String evalCache = 'eC';
-  static String typeRules = 'tR';
-  static String erasedTypes = 'eT';
-  static String typeParameterVariances = 'tPV';
-  static String sharedEmptyArray = 'sEA';
-}
-
 /// Names of fields of collected tear-off parameters object.
 ///
 /// Tear-off getters are created before the Dart classes are initialized, so a
diff --git a/pkg/js_shared/lib/synced/embedded_names.dart b/pkg/js_shared/lib/synced/embedded_names.dart
new file mode 100644
index 0000000..c2f6307
--- /dev/null
+++ b/pkg/js_shared/lib/synced/embedded_names.dart
@@ -0,0 +1,116 @@
+// Copyright (c) 2022, 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.
+
+// @dart=2.12
+
+/// A 'Universe' object used by 'dart:_rti'.
+const RTI_UNIVERSE = 'typeUniverse';
+
+/// An embedded global that contains the property used to store type information
+/// on JavaScript Array instances. This is a Symbol (except for IE11, where is
+/// is a String).
+const ARRAY_RTI_PROPERTY = 'arrayRti';
+
+/// A list of types used in the program e.g. for reflection or encoding of
+/// function types.
+///
+/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
+const TYPES = 'types';
+
+/// Names that are supported by [JS_GET_NAME].
+// TODO(herhut): Make entries lower case (as in fields) and find a better name.
+enum JsGetName {
+  GETTER_PREFIX,
+  SETTER_PREFIX,
+  CALL_PREFIX,
+  CALL_PREFIX0,
+  CALL_PREFIX1,
+  CALL_PREFIX2,
+  CALL_PREFIX3,
+  CALL_PREFIX4,
+  CALL_PREFIX5,
+  CALL_CATCH_ALL,
+  REQUIRED_PARAMETER_PROPERTY,
+  DEFAULT_VALUES_PROPERTY,
+  CALL_NAME_PROPERTY,
+  DEFERRED_ACTION_PROPERTY,
+
+  /// Prefix used for generated type test property on classes.
+  OPERATOR_IS_PREFIX,
+
+  /// Name used for generated function types on classes and methods.
+  SIGNATURE_NAME,
+
+  /// Name of JavaScript property used to store runtime-type information on
+  /// instances of parameterized classes.
+  RTI_NAME,
+
+  /// String representation of the type of the Future class.
+  FUTURE_CLASS_TYPE_NAME,
+
+  /// Field name used for determining if an object or its interceptor has
+  /// JavaScript indexing behavior.
+  IS_INDEXABLE_FIELD_NAME,
+
+  /// String representation of the type of the null class.
+  NULL_CLASS_TYPE_NAME,
+
+  /// String representation of the type of the object class.
+  OBJECT_CLASS_TYPE_NAME,
+
+  /// String representation of the type of the List class.
+  LIST_CLASS_TYPE_NAME,
+
+  /// Property name for Rti._as field.
+  RTI_FIELD_AS,
+
+  /// Property name for Rti._is field.
+  RTI_FIELD_IS,
+}
+
+enum JsBuiltin {
+  /// Returns the JavaScript constructor function for Dart's Object class.
+  /// This can be used for type tests, as in
+  ///
+  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
+  ///     if (JS('bool', '# instanceof #', obj, constructor))
+  ///       ...
+  dartObjectConstructor,
+
+  /// Returns the JavaScript constructor function for the runtime's Closure
+  /// class, the base class of all closure objects.  This can be used for type
+  /// tests, as in
+  ///
+  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
+  ///     if (JS('bool', '# instanceof #', obj, constructor))
+  ///       ...
+  dartClosureConstructor,
+
+  /// Returns true if the given type is a type argument of a js-interop class
+  /// or a supertype of a js-interop class.
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
+  isJsInteropTypeArgument,
+
+  /// Returns the metadata of the given [index].
+  ///
+  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
+  ///                JsBuiltin.getMetadata, index);
+  getMetadata,
+
+  /// Returns the type of the given [index].
+  ///
+  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
+  ///                JsBuiltin.getType, index);
+  getType,
+}
+
+/// Names of fields of the Rti Universe object.
+class RtiUniverseFieldNames {
+  static String evalCache = 'eC';
+  static String typeRules = 'tR';
+  static String erasedTypes = 'eT';
+  static String typeParameterVariances = 'tPV';
+  static String sharedEmptyArray = 'sEA';
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 6e8cd72..66b06a7 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -4,7 +4,7 @@
 
 library _foreign_helper;
 
-import 'dart:_js_embedded_names' show JsGetName, JsBuiltin;
+import 'dart:_js_shared_embedded_names' show JsGetName, JsBuiltin;
 import 'dart:_rti' show Rti;
 
 /// Emits a JavaScript code fragment parametrized by arguments.
@@ -215,13 +215,14 @@
 
 /// Reads an embedded global.
 ///
-/// The [name] should be a constant defined in the `_embedded_names` library.
+/// The [name] should be a constant defined in the `_embedded_names` or
+/// `_js_shared_embedded_names` library.
 external JS_EMBEDDED_GLOBAL(String typeDescription, String name);
 
 /// Instructs the compiler to execute the [builtinName] action at the call-site.
 ///
-/// The [builtin] should be a constant defined in the `_embedded_names`
-/// library.
+/// The [builtin] should be a constant defined in the
+/// `_js_shared_embedded_names` library.
 // Add additional optional arguments if needed. The method is treated internally
 // as a variable argument method.
 external JS_BUILTIN(String typeDescription, JsBuiltin builtin,
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 50f9c4f..fd3ffd1 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -6,19 +6,15 @@
 
 import 'dart:_js_embedded_names'
     show
-        ARRAY_RTI_PROPERTY,
         CURRENT_SCRIPT,
         DEFERRED_LIBRARY_PARTS,
         DEFERRED_PART_URIS,
         DEFERRED_PART_HASHES,
         GET_ISOLATE_TAG,
         INITIALIZE_LOADED_HUNK,
-        INTERCEPTED_NAMES,
         INTERCEPTORS_BY_TAG,
         IS_HUNK_LOADED,
         IS_HUNK_INITIALIZED,
-        JsBuiltin,
-        JsGetName,
         LEAF_TAGS,
         NATIVE_SUPERCLASS_TAG_NAME,
         RUNTIME_METRICS,
@@ -26,6 +22,8 @@
         STATIC_FUNCTION_NAME_PROPERTY_NAME,
         TearOffParametersPropertyNames;
 
+import 'dart:_js_shared_embedded_names' show JsBuiltin, JsGetName;
+
 import 'dart:collection';
 
 import 'dart:async' show Completer, DeferredLoadException, Future, Zone;
diff --git a/sdk/lib/_internal/js_runtime/lib/synced/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/synced/embedded_names.dart
index 9d48e1a..0c99f47 100644
--- a/sdk/lib/_internal/js_runtime/lib/synced/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/synced/embedded_names.dart
@@ -26,22 +26,12 @@
 /// the static function's unique (potentially minified) name.
 const STATIC_FUNCTION_NAME_PROPERTY_NAME = r'$static_name';
 
-/// The name of a property on the constructor function of Dart Object
-/// and interceptor types, used for caching Rti types.
-const CONSTRUCTOR_RTI_CACHE_PROPERTY_NAME = r'$ccache';
-
 /// The name of the embedded global for metadata.
 ///
 /// Use [JsBuiltin.getMetadata] instead of directly accessing this embedded
 /// global.
 const METADATA = 'metadata';
 
-/// A list of types used in the program e.g. for reflection or encoding of
-/// function types.
-///
-/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
-const TYPES = 'types';
-
 /// A JS map from mangled global names to their unmangled names.
 ///
 /// If the program does not use reflection, this embedded global may be empty
@@ -94,11 +84,6 @@
 //    [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
 const ISOLATE_TAG = 'isolateTag';
 
-/// An embedded global that contains the property used to store type information
-/// on JavaScript Array instances. This is a Symbol (except for IE11, where is
-/// is a String).
-const ARRAY_RTI_PROPERTY = 'arrayRti';
-
 /// This embedded global (a function) returns the isolate-specific dispatch-tag
 /// that is used to accelerate interceptor calls.
 const DISPATCH_PROPERTY_NAME = "dispatchPropertyName";
@@ -174,11 +159,6 @@
 /// globals don't clash with it.
 const DEFERRED_INITIALIZED = 'deferredInitialized';
 
-/// A 'Universe' object used by 'dart:_rti'.
-///
-/// This embedded global is used for --experiment-new-rti.
-const RTI_UNIVERSE = 'typeUniverse';
-
 /// An embedded global used to collect and access runtime metrics.
 const RUNTIME_METRICS = 'rm';
 
@@ -188,103 +168,6 @@
 /// An embedded global used to collect and access startup metrics.
 const STARTUP_METRICS = 'sm';
 
-/// Names that are supported by [JS_GET_NAME].
-// TODO(herhut): Make entries lower case (as in fields) and find a better name.
-enum JsGetName {
-  GETTER_PREFIX,
-  SETTER_PREFIX,
-  CALL_PREFIX,
-  CALL_PREFIX0,
-  CALL_PREFIX1,
-  CALL_PREFIX2,
-  CALL_PREFIX3,
-  CALL_PREFIX4,
-  CALL_PREFIX5,
-  CALL_CATCH_ALL,
-  REQUIRED_PARAMETER_PROPERTY,
-  DEFAULT_VALUES_PROPERTY,
-  CALL_NAME_PROPERTY,
-  DEFERRED_ACTION_PROPERTY,
-
-  /// Prefix used for generated type test property on classes.
-  OPERATOR_IS_PREFIX,
-
-  /// Name used for generated function types on classes and methods.
-  SIGNATURE_NAME,
-
-  /// Name of JavaScript property used to store runtime-type information on
-  /// instances of parameterized classes.
-  RTI_NAME,
-
-  /// String representation of the type of the Future class.
-  FUTURE_CLASS_TYPE_NAME,
-
-  /// Field name used for determining if an object or its interceptor has
-  /// JavaScript indexing behavior.
-  IS_INDEXABLE_FIELD_NAME,
-
-  /// String representation of the type of the null class.
-  NULL_CLASS_TYPE_NAME,
-
-  /// String representation of the type of the object class.
-  OBJECT_CLASS_TYPE_NAME,
-
-  /// String representation of the type of the List class.
-  LIST_CLASS_TYPE_NAME,
-
-  /// Property name for Rti._as field.
-  RTI_FIELD_AS,
-
-  /// Property name for Rti._is field.
-  RTI_FIELD_IS,
-}
-
-enum JsBuiltin {
-  /// Returns the JavaScript constructor function for Dart's Object class.
-  /// This can be used for type tests, as in
-  ///
-  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
-  ///     if (JS('bool', '# instanceof #', obj, constructor))
-  ///       ...
-  dartObjectConstructor,
-
-  /// Returns the JavaScript constructor function for the runtime's Closure
-  /// class, the base class of all closure objects.  This can be used for type
-  /// tests, as in
-  ///
-  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
-  ///     if (JS('bool', '# instanceof #', obj, constructor))
-  ///       ...
-  dartClosureConstructor,
-
-  /// Returns true if the given type is a type argument of a js-interop class
-  /// or a supertype of a js-interop class.
-  ///
-  ///     JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
-  isJsInteropTypeArgument,
-
-  /// Returns the metadata of the given [index].
-  ///
-  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
-  ///                JsBuiltin.getMetadata, index);
-  getMetadata,
-
-  /// Returns the type of the given [index].
-  ///
-  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
-  ///                JsBuiltin.getType, index);
-  getType,
-}
-
-/// Names of fields of the Rti Universe object.
-class RtiUniverseFieldNames {
-  static String evalCache = 'eC';
-  static String typeRules = 'tR';
-  static String erasedTypes = 'eT';
-  static String typeParameterVariances = 'tPV';
-  static String sharedEmptyArray = 'sEA';
-}
-
 /// Names of fields of collected tear-off parameters object.
 ///
 /// Tear-off getters are created before the Dart classes are initialized, so a
diff --git a/sdk/lib/_internal/js_shared/lib/rti.dart b/sdk/lib/_internal/js_shared/lib/rti.dart
index 356298b..b7c9881 100644
--- a/sdk/lib/_internal/js_shared/lib/rti.dart
+++ b/sdk/lib/_internal/js_shared/lib/rti.dart
@@ -18,24 +18,16 @@
         RAW_DART_FUNCTION_REF,
         TYPE_REF,
         LEGACY_TYPE_REF;
-
 import 'dart:_interceptors'
     show JavaScriptFunction, JSArray, JSNull, JSUnmodifiableArray;
-
 import 'dart:_js_names' show unmangleGlobalNameIfPreservedAnyways;
-
-import 'dart:_js_embedded_names'
-    show
-        JsBuiltin,
-        JsGetName,
-        RtiUniverseFieldNames,
-        ARRAY_RTI_PROPERTY,
-        CONSTRUCTOR_RTI_CACHE_PROPERTY_NAME,
-        RTI_UNIVERSE,
-        TYPES;
-
+import 'dart:_js_shared_embedded_names';
 import 'dart:_recipe_syntax';
 
+/// The name of a property on the constructor function of Dart Object
+/// and interceptor types, used for caching Rti types.
+const CONSTRUCTOR_RTI_CACHE_PROPERTY_NAME = r'$ccache';
+
 // The top type `Object?` is used throughout this library even when values are
 // not nullable or have narrower types in order to avoid incurring type checks
 // before the type checking infrastructure has been set up.
diff --git a/sdk/lib/_internal/js_shared/lib/synced/embedded_names.dart b/sdk/lib/_internal/js_shared/lib/synced/embedded_names.dart
new file mode 100644
index 0000000..c2f6307
--- /dev/null
+++ b/sdk/lib/_internal/js_shared/lib/synced/embedded_names.dart
@@ -0,0 +1,116 @@
+// Copyright (c) 2022, 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.
+
+// @dart=2.12
+
+/// A 'Universe' object used by 'dart:_rti'.
+const RTI_UNIVERSE = 'typeUniverse';
+
+/// An embedded global that contains the property used to store type information
+/// on JavaScript Array instances. This is a Symbol (except for IE11, where is
+/// is a String).
+const ARRAY_RTI_PROPERTY = 'arrayRti';
+
+/// A list of types used in the program e.g. for reflection or encoding of
+/// function types.
+///
+/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
+const TYPES = 'types';
+
+/// Names that are supported by [JS_GET_NAME].
+// TODO(herhut): Make entries lower case (as in fields) and find a better name.
+enum JsGetName {
+  GETTER_PREFIX,
+  SETTER_PREFIX,
+  CALL_PREFIX,
+  CALL_PREFIX0,
+  CALL_PREFIX1,
+  CALL_PREFIX2,
+  CALL_PREFIX3,
+  CALL_PREFIX4,
+  CALL_PREFIX5,
+  CALL_CATCH_ALL,
+  REQUIRED_PARAMETER_PROPERTY,
+  DEFAULT_VALUES_PROPERTY,
+  CALL_NAME_PROPERTY,
+  DEFERRED_ACTION_PROPERTY,
+
+  /// Prefix used for generated type test property on classes.
+  OPERATOR_IS_PREFIX,
+
+  /// Name used for generated function types on classes and methods.
+  SIGNATURE_NAME,
+
+  /// Name of JavaScript property used to store runtime-type information on
+  /// instances of parameterized classes.
+  RTI_NAME,
+
+  /// String representation of the type of the Future class.
+  FUTURE_CLASS_TYPE_NAME,
+
+  /// Field name used for determining if an object or its interceptor has
+  /// JavaScript indexing behavior.
+  IS_INDEXABLE_FIELD_NAME,
+
+  /// String representation of the type of the null class.
+  NULL_CLASS_TYPE_NAME,
+
+  /// String representation of the type of the object class.
+  OBJECT_CLASS_TYPE_NAME,
+
+  /// String representation of the type of the List class.
+  LIST_CLASS_TYPE_NAME,
+
+  /// Property name for Rti._as field.
+  RTI_FIELD_AS,
+
+  /// Property name for Rti._is field.
+  RTI_FIELD_IS,
+}
+
+enum JsBuiltin {
+  /// Returns the JavaScript constructor function for Dart's Object class.
+  /// This can be used for type tests, as in
+  ///
+  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
+  ///     if (JS('bool', '# instanceof #', obj, constructor))
+  ///       ...
+  dartObjectConstructor,
+
+  /// Returns the JavaScript constructor function for the runtime's Closure
+  /// class, the base class of all closure objects.  This can be used for type
+  /// tests, as in
+  ///
+  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
+  ///     if (JS('bool', '# instanceof #', obj, constructor))
+  ///       ...
+  dartClosureConstructor,
+
+  /// Returns true if the given type is a type argument of a js-interop class
+  /// or a supertype of a js-interop class.
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
+  isJsInteropTypeArgument,
+
+  /// Returns the metadata of the given [index].
+  ///
+  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
+  ///                JsBuiltin.getMetadata, index);
+  getMetadata,
+
+  /// Returns the type of the given [index].
+  ///
+  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
+  ///                JsBuiltin.getType, index);
+  getType,
+}
+
+/// Names of fields of the Rti Universe object.
+class RtiUniverseFieldNames {
+  static String evalCache = 'eC';
+  static String typeRules = 'tR';
+  static String erasedTypes = 'eT';
+  static String typeParameterVariances = 'tPV';
+  static String sharedEmptyArray = 'sEA';
+}
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index 5a357e5..5cbab01 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -176,6 +176,11 @@
       categories: "",
       documented: false,
       platforms: DART2JS_PLATFORM),
+  "_js_shared_embedded_names": const LibraryInfo(
+      "_internal/js_shared/lib/synced/embedded_names.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
   "_async_await_error_codes": const LibraryInfo(
       "_internal/js_runtime/lib/synced/async_await_error_codes.dart",
       categories: "",
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index 6f33d88..4c5eb19 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -386,6 +386,9 @@
       "_js_embedded_names": {
         "uri": "_internal/js_runtime/lib/synced/embedded_names.dart"
       },
+      "_js_shared_embedded_names": {
+        "uri": "_internal/js_shared/lib/synced/embedded_names.dart"
+      },
       "_async_await_error_codes": {
         "uri": "_internal/js_runtime/lib/synced/async_await_error_codes.dart"
       },
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index ed11fa5..c09c34e 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -354,6 +354,9 @@
     _js_embedded_names:
       uri: "_internal/js_runtime/lib/synced/embedded_names.dart"
 
+    _js_shared_embedded_names:
+      uri: "_internal/js_shared/lib/synced/embedded_names.dart"
+
     _async_await_error_codes:
       uri: "_internal/js_runtime/lib/synced/async_await_error_codes.dart"
 
diff --git a/tests/web/internal/rti/subtype_test.dart b/tests/web/internal/rti/subtype_test.dart
index d4f0c48..b6ceded 100644
--- a/tests/web/internal/rti/subtype_test.dart
+++ b/tests/web/internal/rti/subtype_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:_foreign_helper' show JS, JS_GET_NAME, TYPE_REF;
-import 'dart:_js_embedded_names' show JsGetName;
+import 'dart:_js_shared_embedded_names' show JsGetName;
 import 'dart:_rti' as rti;
 import 'package:expect/expect.dart';
 
diff --git a/tests/web_2/internal/rti/subtype_test.dart b/tests/web_2/internal/rti/subtype_test.dart
index 3ffea446..5cdb5ce 100644
--- a/tests/web_2/internal/rti/subtype_test.dart
+++ b/tests/web_2/internal/rti/subtype_test.dart
@@ -5,7 +5,7 @@
 // @dart = 2.7
 
 import 'dart:_foreign_helper' show JS, JS_GET_NAME, TYPE_REF;
-import 'dart:_js_embedded_names' show JsGetName;
+import 'dart:_js_shared_embedded_names' show JsGetName;
 import 'dart:_rti' as rti;
 
 import 'subtype_utils.dart';
diff --git a/tools/VERSION b/tools/VERSION
index df3ca95..e0ae251 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 146
+PRERELEASE 147
 PRERELEASE_PATCH 0
\ No newline at end of file