Version 2.18.0-91.0.dev

Merge commit '4f0ed6a45cb778c02e1351399d63ddc917f61404' into 'dev'
diff --git a/.github/move.yml b/.github/move.yml
deleted file mode 100644
index bf0cceb..0000000
--- a/.github/move.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-# Configuration for move-issues - https://github.com/dessant/move-issues
-
-# Delete the command comment when it contains no other content
-deleteCommand: true
-
-# Close the source issue after moving
-closeSourceIssue: true
-
-# Lock the source issue after moving
-lockSourceIssue: false
-
-# Mention issue and comment authors
-mentionAuthors: true
-
-# Preserve mentions in the issue content
-keepContentMentions: true
-
-# Set custom aliases for targets
-aliases:
-  flutter: flutter/flutter
-  flutter-intellij: flutter/flutter-intellij
diff --git a/.github/no-response.yml b/.github/no-response.yml
deleted file mode 100644
index 81cec3e..0000000
--- a/.github/no-response.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Configuration for probot-no-response - https://github.com/probot/no-response
-
-# Number of days of inactivity before an issue is closed for lack of response.
-daysUntilClose: 21
-
-# Label requiring a response.
-responseRequiredLabel: "needs-info"
-
-# Comment to post when closing an Issue for lack of response.
-closeComment: >-
-  Without additional information, we are unfortunately not sure how to
-  resolve this issue. We are therefore reluctantly going to close this
-  bug for now. Please don't hesitate to comment on the bug if you have
-  any more information for us; we will reopen it right away!
-
-  Thanks for your contribution.
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
index 6fd8abf..cf79edf 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
@@ -158,13 +158,13 @@
   /// offset is within the given [node], or `null` if the context does not
   /// impose any type.
   DartType? computeContextType(AstNode node, int offset) {
-    var type = node
-        .accept(_ContextTypeVisitor(typeProvider, offset))
-        ?.resolveToBound(typeProvider.objectType);
-    if (type == null || type.isDynamic) {
+    final contextType = node.accept(
+      _ContextTypeVisitor(typeProvider, offset),
+    );
+    if (contextType == null || contextType.isDynamic) {
       return null;
     }
-    return type;
+    return typeSystem.resolveToBound(contextType);
   }
 
   /// Return the element kind used to compute relevance for the given [element].
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index b809dbe..ef27adf 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -42,7 +42,10 @@
     }
 
     // Determine the target expression's type.
-    var type = expression.staticType?.resolveToBound(request.objectType);
+    final expressionType = expression.staticType;
+    var type = expressionType != null
+        ? request.libraryElement.typeSystem.resolveToBound(expressionType)
+        : null;
     if (type == null || type.isDynamic) {
       // If the expression does not provide a good type, then attempt to get a
       // better type from the element.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart b/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart
index a1f240b..c6a9dc9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart
@@ -80,6 +80,77 @@
   @override
   String get lintCode => LintNames.sort_constructors_first;
 
+  @FailingTest(
+    reason: 'The beginToken is the comment, which has no previous token.',
+    issue: 'https://github.com/dart-lang/sdk/issues/48966',
+  )
+  Future<void> test_hasComment() async {
+    await resolveTestCode('''
+class A {
+  void foo() {}
+  /// comment
+  A();
+}
+''');
+    await assertHasFix('''
+class A {
+  /// comment
+  A();
+  void foo() {}
+}
+''');
+  }
+
+  @FailingTest(
+    reason: 'The beginToken is the comment, which has no previous token.',
+    issue: 'https://github.com/dart-lang/sdk/issues/48966',
+  )
+  Future<void> test_hasComment_hasMetadata_afterComment() async {
+    await resolveTestCode('''
+const a = 0;
+
+class A {
+  void foo() {}
+  /// comment
+  @a
+  A();
+}
+''');
+    await assertHasFix('''
+const a = 0;
+
+class A {
+  /// comment
+  @a
+  A();
+  void foo() {}
+}
+''');
+  }
+
+  Future<void> test_hasComment_hasMetadata_beforeComment() async {
+    await resolveTestCode('''
+const a = 0;
+
+class A {
+  void foo() {}
+  @a
+  /// comment
+  A();
+}
+''');
+    await assertHasFix('''
+const a = 0;
+
+class A {
+  @a
+  /// comment
+  A();
+  void foo() {}
+}
+''');
+  }
+
   Future<void> test_one_fix() async {
     await resolveTestCode('''
 class A {
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 4e91889..4462b02 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -2,6 +2,7 @@
 * Deprecated `ParameterElement.isNotOptional`, use `isRequired` instead.
 * Deprecated `ResourceProviderMixin.newFile2`, use `newFile` instead.
 * Deprecated `ResourceProviderMixin.newAnalysisOptionsYamlFile2`, use `newAnalysisOptionsYamlFile` instead.
+* Deprecated `DartType.resolveToBound`, use `TypeSystem.resolveToBound` instead.
 
 ## 4.0.0
 * Removed deprecated `UriKind` and `Source.uriKind`.
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 2f479bd..806186f 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -176,6 +176,7 @@
   ///
   /// For any other type, returns `this`. Applies recursively -- if the bound is
   /// itself a type parameter, that is resolved too.
+  @Deprecated('Use TypeSystem.resolveToBound() instead')
   DartType resolveToBound(DartType objectType);
 }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index dcef43d..113b883 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1063,6 +1063,7 @@
     return false;
   }
 
+  @Deprecated('Use TypeSystem.resolveToBound() instead')
   @override
   DartType resolveToBound(DartType objectType) => this;
 
@@ -1201,6 +1202,7 @@
     return parameters.contains(element);
   }
 
+  @Deprecated('Use TypeSystem.resolveToBound() instead')
   @override
   DartType resolveToBound(DartType objectType) {
     final promotedBound = this.promotedBound;
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index d420c963..5208c75 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -1468,26 +1468,26 @@
   @override
   DartType resolveToBound(DartType type) {
     if (type is TypeParameterTypeImpl) {
-      var element = type.element;
+      final promotedBound = type.promotedBound;
+      if (promotedBound != null) {
+        return resolveToBound(promotedBound);
+      }
 
-      var bound = element.bound;
+      final bound = type.element.bound;
       if (bound == null) {
-        return typeProvider.objectType;
+        return isNonNullableByDefault ? objectQuestion : objectStar;
       }
 
-      NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix;
-      NullabilitySuffix newNullabilitySuffix;
-      if (nullabilitySuffix == NullabilitySuffix.question ||
-          bound.nullabilitySuffix == NullabilitySuffix.question) {
-        newNullabilitySuffix = NullabilitySuffix.question;
-      } else if (nullabilitySuffix == NullabilitySuffix.star ||
-          bound.nullabilitySuffix == NullabilitySuffix.star) {
-        newNullabilitySuffix = NullabilitySuffix.star;
-      } else {
-        newNullabilitySuffix = NullabilitySuffix.none;
-      }
+      final resolved = resolveToBound(bound) as TypeImpl;
 
-      var resolved = resolveToBound(bound) as TypeImpl;
+      final newNullabilitySuffix = uniteNullabilities(
+        uniteNullabilities(
+          type.nullabilitySuffix,
+          bound.nullabilitySuffix,
+        ),
+        resolved.nullabilitySuffix,
+      );
+
       return resolved.withNullability(newNullabilitySuffix);
     }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 6d8741a..0906db3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -233,13 +233,6 @@
         contextType: contextType);
   }
 
-  /// If the given [type] is a type parameter, resolve it to the type that should
-  /// be used when looking up members. Otherwise, return the original type.
-  ///
-  /// TODO(scheglov) this is duplicate
-  DartType _resolveTypeParameter(DartType type) =>
-      type.resolveToBound(_typeProvider.objectType);
-
   void _resolveUnsupportedOperator(BinaryExpressionImpl node,
       {required DartType? contextType}) {
     node.leftOperand.accept(_resolver);
@@ -304,7 +297,7 @@
     }
 
     var leftType = leftOperand.typeOrThrow;
-    leftType = _resolveTypeParameter(leftType);
+    leftType = _typeSystem.resolveToBound(leftType);
 
     if (identical(leftType, NeverTypeImpl.instance)) {
       _resolver.errorReporter.reportErrorForNode(
@@ -354,7 +347,7 @@
       leftType = leftOperand.extendedType!;
     } else {
       leftType = leftOperand.typeOrThrow;
-      leftType = _resolveTypeParameter(leftType);
+      leftType = _typeSystem.resolveToBound(leftType);
     }
 
     if (identical(leftType, NeverTypeImpl.instance)) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
index f43eecf..5cebadf 100644
--- a/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
@@ -21,6 +22,8 @@
   CommentReferenceResolver(this._typeProvider, this._resolver)
       : _typePropertyResolver = _resolver.typePropertyResolver;
 
+  TypeSystemImpl get _typeSystem => _resolver.typeSystem;
+
   /// Resolves [commentReference].
   void resolve(CommentReference commentReference) {
     _resolver.errorReporter.lockLevel++;
@@ -150,8 +153,9 @@
         if (enclosingExtension == null) {
           return null;
         }
-        var extendedType = enclosingExtension.extendedType
-            .resolveToBound(_typeProvider.objectType);
+        var extendedType = _typeSystem.resolveToBound(
+          enclosingExtension.extendedType,
+        );
         if (extendedType is InterfaceType) {
           enclosingType = extendedType;
         } else if (extendedType is FunctionType) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index dceec2d..4784ae4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_schema.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
@@ -22,6 +23,8 @@
     required ResolverVisitor resolver,
   }) : _resolver = resolver;
 
+  TypeSystemImpl get _typeSystem => _resolver.typeSystem;
+
   void resolveElement(ForElementImpl node, CollectionLiteralContext? context) {
     var forLoopParts = node.forLoopParts;
     void visitBody() {
@@ -57,8 +60,7 @@
   DartType? _computeForEachElementType(Expression iterable, bool isAsync) {
     var iterableType = iterable.staticType;
     if (iterableType == null) return null;
-    iterableType =
-        iterableType.resolveToBound(_resolver.typeProvider.objectType);
+    iterableType = _typeSystem.resolveToBound(iterableType);
 
     ClassElement iteratedElement = isAsync
         ? _resolver.typeProvider.streamElement
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index e7d3b26..8fdaa1a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -868,15 +868,6 @@
     }
   }
 
-  /// If the given [type] is a type parameter, replace with its bound.
-  /// Otherwise, return the original type.
-  DartType _resolveTypeParameter(DartType type) {
-    if (type is TypeParameterType) {
-      return type.resolveToBound(_resolver.typeProvider.objectType);
-    }
-    return type;
-  }
-
   /// We have identified that [node] is not a real [MethodInvocation],
   /// because it does not invoke a method, but instead invokes the result
   /// of a getter execution, or implicitly invokes the `call` method of
@@ -885,7 +876,7 @@
   void _rewriteAsFunctionExpressionInvocation(
       MethodInvocationImpl node, DartType getterReturnType,
       {required DartType? contextType}) {
-    var targetType = _resolveTypeParameter(getterReturnType);
+    var targetType = _typeSystem.resolveToBound(getterReturnType);
     _inferenceHelper.recordStaticType(node.methodName, targetType,
         contextType: contextType);
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 8e8bce1..47bfe31 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -68,7 +68,7 @@
     }
 
     var targetType = target.typeOrThrow;
-    targetType = _resolveTypeParameter(targetType);
+    targetType = _typeSystem.resolveToBound(targetType);
 
     if (targetType.isVoid) {
       // TODO(scheglov) Report directly in TypePropertyResolver?
@@ -815,15 +815,6 @@
     );
   }
 
-  /// If the given [type] is a type parameter, replace with its bound.
-  /// Otherwise, return the original type.
-  DartType _resolveTypeParameter(DartType type) {
-    if (type is TypeParameterType) {
-      return type.resolveToBound(_resolver.typeProvider.objectType);
-    }
-    return type;
-  }
-
   PropertyElementResolverResult _toIndexResult(ResolutionResult result) {
     var readElement = result.getter;
     var writeElement = result.setter;
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index fc870ea..6e9f0cc 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -282,7 +282,7 @@
     bool ifNullSafe = false,
   }) {
     if (_typeSystem.isNonNullableByDefault ? ifNullSafe : ifLegacy) {
-      return type.resolveToBound(_typeProvider.objectType);
+      return _typeSystem.resolveToBound(type);
     } else {
       return type;
     }
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index d5a1aac..039fbff 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2393,7 +2393,7 @@
     // The object being iterated has to implement Iterable<T> for some T that
     // is assignable to the variable's type.
     // TODO(rnystrom): Move this into mostSpecificTypeArgument()?
-    iterableType = iterableType.resolveToBound(_typeProvider.objectType);
+    iterableType = typeSystem.resolveToBound(iterableType);
 
     var requiredSequenceType = awaitKeyword != null
         ? _typeProvider.streamDynamicType
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart
index 6b7dd6c..42ac2f3 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -486,7 +486,7 @@
       return null;
     }
 
-    return declarationBuilder.fromElement.classDeclaration(
+    return declarationBuilder.fromElement.classElement(
       superType.element,
     );
   }
diff --git a/pkg/analyzer/lib/src/summary2/macro_declarations.dart b/pkg/analyzer/lib/src/summary2/macro_declarations.dart
index 47bcc2b..21707bc 100644
--- a/pkg/analyzer/lib/src/summary2/macro_declarations.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_declarations.dart
@@ -8,6 +8,8 @@
     as macro;
 import 'package:analyzer/dart/ast/ast.dart' as ast;
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/dart/element/type.dart';
 
 class ClassDeclarationImpl extends macro.ClassDeclarationImpl {
   late final ClassElement element;
@@ -43,7 +45,7 @@
   /// corresponding elements. So, we can access them uniformly via interfaces,
   /// mixins, etc.
   void transferToElements() {
-    for (final entry in fromNode._classNodes.entries) {
+    for (final entry in fromNode._classMap.entries) {
       final element = entry.key.declaredElement as ClassElement;
       final declaration = entry.value;
       declaration.element = element;
@@ -54,51 +56,86 @@
 
 class DeclarationBuilderFromElement {
   final Map<ClassElement, ClassDeclarationImpl> _classMap = Map.identity();
+  final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl>
+      _typeParameterMap = Map.identity();
 
-  macro.ClassDeclarationImpl classDeclaration(ClassElement element) {
-    return _classMap[element] ??= _classDeclaration(element);
+  macro.ClassDeclarationImpl classElement(ClassElement element) {
+    return _classMap[element] ??= _classElement(element);
   }
 
-  ClassDeclarationImpl _classDeclaration(ClassElement element) {
+  macro.TypeParameterDeclarationImpl typeParameter(
+    TypeParameterElement element,
+  ) {
+    return _typeParameterMap[element] ??= _typeParameter(element);
+  }
+
+  ClassDeclarationImpl _classElement(ClassElement element) {
     assert(!_classMap.containsKey(element));
     return ClassDeclarationImpl._(
       id: macro.RemoteInstance.uniqueId,
-      identifier: _identifierFromName(element.name),
-      typeParameters: [], // TODO _buildTypeParameters(node.typeParameters),
-      interfaces: [], // TODO _buildTypeAnnotations(node.implementsClause?.interfaces),
-      isAbstract: false, // TODO node.abstractKeyword != null,
+      identifier: _identifier(element.name),
+      typeParameters: element.typeParameters.map(_typeParameter).toList(),
+      interfaces: element.interfaces.map(_dartType).toList(),
+      isAbstract: element.isAbstract,
       isExternal: false,
-      mixins: [], // TODO _buildTypeAnnotations(node.withClause?.mixinTypes),
-      superclass: null,
-      // TODO(scheglov) implement
-      // superclass: node.extendsClause?.superclass.mapOrNull(
-      //   _buildTypeAnnotation,
-      // ),
+      mixins: element.mixins.map(_dartType).toList(),
+      superclass: element.supertype.mapOrNull(_dartType),
     )..element = element;
   }
 
-  macro.IdentifierImpl _identifierFromName(String name) {
+  macro.TypeAnnotationImpl _dartType(DartType type) {
+    if (type is InterfaceType) {
+      return macro.NamedTypeAnnotationImpl(
+        id: macro.RemoteInstance.uniqueId,
+        isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
+        identifier: _identifier(type.element.name),
+        typeArguments: type.typeArguments.map(_dartType).toList(),
+      );
+    } else if (type is TypeParameterType) {
+      return macro.NamedTypeAnnotationImpl(
+        id: macro.RemoteInstance.uniqueId,
+        isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
+        identifier: _identifier(type.element.name),
+        typeArguments: const [],
+      );
+    } else {
+      // TODO(scheglov) other types
+      throw UnimplementedError('(${type.runtimeType}) $type');
+    }
+  }
+
+  macro.IdentifierImpl _identifier(String name) {
     return _IdentifierImpl(
       id: macro.RemoteInstance.uniqueId,
       name: name,
     );
   }
+
+  macro.TypeParameterDeclarationImpl _typeParameter(
+    TypeParameterElement element,
+  ) {
+    return macro.TypeParameterDeclarationImpl(
+      id: macro.RemoteInstance.uniqueId,
+      identifier: _identifier(element.name),
+      bound: element.bound.mapOrNull(_dartType),
+    );
+  }
 }
 
 class DeclarationBuilderFromNode {
-  final Map<ast.ClassDeclaration, ClassDeclarationImpl> _classNodes =
+  final Map<ast.ClassDeclaration, ClassDeclarationImpl> _classMap =
       Map.identity();
 
   macro.ClassDeclarationImpl classDeclaration(
     ast.ClassDeclaration node,
   ) {
-    return _classNodes[node] ??= _classDeclaration(node);
+    return _classMap[node] ??= _classDeclaration(node);
   }
 
   ClassDeclarationImpl _classDeclaration(
     ast.ClassDeclaration node,
   ) {
-    assert(!_classNodes.containsKey(node));
+    assert(!_classMap.containsKey(node));
     return ClassDeclarationImpl._(
       id: macro.RemoteInstance.uniqueId,
       identifier: _identifier(node.name),
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index d105672..6873d5f 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -789,6 +789,7 @@
     expect(types[1], stringNone);
   }
 
+  @deprecated
   void test_resolveToBound() {
     var type = functionTypeNone(
       typeFormals: [],
@@ -1235,6 +1236,7 @@
     expect(0 == typeA.hashCode, isFalse);
   }
 
+  @deprecated
   void test_resolveToBound() {
     var type = interfaceTypeStar(ElementFactory.classElement2('A'));
 
@@ -1414,6 +1416,7 @@
     expect(type.element, element);
   }
 
+  @deprecated
   void test_resolveToBound_bound() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1422,6 +1425,7 @@
     expect(type.resolveToBound(objectNone), interfaceTypeStar(classS));
   }
 
+  @deprecated
   void test_resolveToBound_bound_nullableInner() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1430,6 +1434,7 @@
     expect(type.resolveToBound(objectNone), same(element.bound));
   }
 
+  @deprecated
   void test_resolveToBound_bound_nullableInnerOuter() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1439,6 +1444,7 @@
     expect(type.resolveToBound(objectNone), same(element.bound));
   }
 
+  @deprecated
   void test_resolveToBound_bound_nullableInnerStarOuter() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1449,6 +1455,7 @@
         type.resolveToBound(objectNone), equals(interfaceTypeQuestion(classS)));
   }
 
+  @deprecated
   void test_resolveToBound_bound_nullableOuter() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1459,6 +1466,7 @@
         type.resolveToBound(objectNone), equals(interfaceTypeQuestion(classS)));
   }
 
+  @deprecated
   void test_resolveToBound_bound_starInner() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1467,6 +1475,7 @@
     expect(type.resolveToBound(objectNone), same(element.bound));
   }
 
+  @deprecated
   void test_resolveToBound_bound_starInnerNullableOuter() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1476,6 +1485,7 @@
     expect(type.resolveToBound(objectNone), same(element.bound));
   }
 
+  @deprecated
   void test_resolveToBound_bound_starOuter() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1485,6 +1495,7 @@
     expect(type.resolveToBound(objectNone), interfaceTypeStar(classS));
   }
 
+  @deprecated
   void test_resolveToBound_nestedBound() {
     ClassElementImpl classS = class_(name: 'A');
     TypeParameterElementImpl elementE = TypeParameterElementImpl('E', -1);
@@ -1496,6 +1507,7 @@
     expect(typeF.resolveToBound(objectNone), interfaceTypeStar(classS));
   }
 
+  @deprecated
   void test_resolveToBound_promotedBound_interfaceType() {
     var A = class_(name: 'A');
     var A_none = interfaceTypeNone(A);
@@ -1505,6 +1517,7 @@
     expect(T_A.resolveToBound(objectQuestion), A_none);
   }
 
+  @deprecated
   void test_resolveToBound_promotedBound_typeParameterType_interfaceType() {
     var A = class_(name: 'A');
     var A_none = interfaceTypeNone(A);
@@ -1517,6 +1530,7 @@
     expect(U_T.resolveToBound(objectQuestion), A_none);
   }
 
+  @deprecated
   void test_resolveToBound_unbound() {
     TypeParameterTypeImpl type =
         typeParameterTypeStar(TypeParameterElementImpl('E', -1));
@@ -1597,6 +1611,7 @@
     expect(_voidType.isVoid, isTrue);
   }
 
+  @deprecated
   void test_resolveToBound() {
     // Returns this.
     expect(_voidType.resolveToBound(objectNone), same(_voidType));
diff --git a/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart b/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart
new file mode 100644
index 0000000..b733568
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart
@@ -0,0 +1,225 @@
+// 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.
+
+import 'package:analyzer/dart/element/type.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../generated/type_system_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ResolveToBoundTest);
+    defineReflectiveTests(ResolveToBoundWithoutNullSafetyTest);
+  });
+}
+
+@reflectiveTest
+class ResolveToBoundTest extends AbstractTypeSystemTest {
+  test_dynamic() {
+    _check(dynamicType, 'dynamic');
+  }
+
+  test_functionType() {
+    _check(
+      functionTypeNone(returnType: voidNone),
+      'void Function()',
+    );
+  }
+
+  test_interfaceType() {
+    _check(intNone, 'int');
+    _check(intQuestion, 'int?');
+    _check(intStar, 'int*');
+  }
+
+  test_typeParameter_bound() {
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T', bound: intNone),
+      ),
+      'int',
+    );
+
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T', bound: intQuestion),
+      ),
+      'int?',
+    );
+
+    _check(
+      typeParameterTypeStar(
+        typeParameter('T', bound: intStar),
+      ),
+      'int*',
+    );
+  }
+
+  test_typeParameter_bound_functionType() {
+    _check(
+      typeParameterTypeNone(
+        typeParameter(
+          'T',
+          bound: functionTypeNone(
+            returnType: voidNone,
+          ),
+        ),
+      ),
+      'void Function()',
+    );
+  }
+
+  test_typeParameter_bound_nested_noBound() {
+    final T = typeParameter('T');
+    final U = typeParameter(
+      'U',
+      bound: typeParameterTypeNone(T),
+    );
+    _check(typeParameterTypeNone(U), 'Object?');
+  }
+
+  test_typeParameter_bound_nested_none() {
+    final T = typeParameter('T', bound: intNone);
+    final U = typeParameter(
+      'U',
+      bound: typeParameterTypeNone(T),
+    );
+    _check(typeParameterTypeNone(U), 'int');
+  }
+
+  test_typeParameter_bound_nested_none_outerNullable() {
+    final T = typeParameter('T', bound: intNone);
+    final U = typeParameter(
+      'U',
+      bound: typeParameterTypeQuestion(T),
+    );
+    _check(typeParameterTypeNone(U), 'int?');
+  }
+
+  test_typeParameter_bound_nested_question() {
+    final T = typeParameter('T', bound: intQuestion);
+    final U = typeParameter(
+      'U',
+      bound: typeParameterTypeNone(T),
+    );
+    _check(typeParameterTypeNone(U), 'int?');
+  }
+
+  test_typeParameter_bound_nullableInner() {
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T', bound: intQuestion),
+      ),
+      'int?',
+    );
+  }
+
+  test_typeParameter_bound_nullableInnerOuter() {
+    _check(
+      typeParameterTypeQuestion(
+        typeParameter('T', bound: intQuestion),
+      ),
+      'int?',
+    );
+  }
+
+  test_typeParameter_bound_nullableOuter() {
+    _check(
+      typeParameterTypeQuestion(
+        typeParameter('T', bound: intNone),
+      ),
+      'int?',
+    );
+  }
+
+  test_typeParameter_noBound() {
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T'),
+      ),
+      'Object?',
+    );
+  }
+
+  test_typeParameter_promotedBound() {
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T', bound: numNone),
+        promotedBound: intNone,
+      ),
+      'int',
+    );
+
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T', bound: numQuestion),
+        promotedBound: intQuestion,
+      ),
+      'int?',
+    );
+
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T', bound: numStar),
+        promotedBound: intStar,
+      ),
+      'int*',
+    );
+  }
+
+  test_void() {
+    _check(voidNone, 'void');
+  }
+
+  void _check(DartType type, String expectedStr) {
+    var result = typeSystem.resolveToBound(type);
+    var resultStr = _typeString(result);
+    expect(resultStr, expectedStr);
+  }
+
+  String _typeString(DartType type) {
+    return type.getDisplayString(withNullability: true);
+  }
+}
+
+@reflectiveTest
+class ResolveToBoundWithoutNullSafetyTest
+    extends AbstractTypeSystemWithoutNullSafetyTest {
+  test_dynamic() {
+    _check(dynamicType, 'dynamic');
+  }
+
+  test_typeParameter_bound() {
+    _check(
+      typeParameterTypeStar(
+        typeParameter('T', bound: intStar),
+      ),
+      'int*',
+    );
+  }
+
+  test_typeParameter_noBound() {
+    _check(
+      typeParameterTypeNone(
+        typeParameter('T'),
+      ),
+      'Object*',
+    );
+  }
+
+  test_void() {
+    _check(voidNone, 'void');
+  }
+
+  void _check(DartType type, String expectedStr) {
+    var result = typeSystem.resolveToBound(type);
+    var resultStr = _typeString(result);
+    expect(resultStr, expectedStr);
+  }
+
+  String _typeString(DartType type) {
+    return type.getDisplayString(withNullability: true);
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart
index f3019b9..8d78853 100644
--- a/pkg/analyzer/test/src/dart/element/test_all.dart
+++ b/pkg/analyzer/test/src/dart/element/test_all.dart
@@ -21,6 +21,7 @@
 import 'nullability_eliminator_test.dart' as nullability_eliminator;
 import 'nullable_test.dart' as nullable;
 import 'replace_top_bottom_test.dart' as replace_top_bottom;
+import 'resolve_to_bound_test.dart' as resolve_to_bound;
 import 'runtime_type_equality_test.dart' as runtime_type_equality;
 import 'subtype_test.dart' as subtype;
 import 'top_merge_test.dart' as top_merge;
@@ -52,6 +53,7 @@
     nullability_eliminator.main();
     nullable.main();
     replace_top_bottom.main();
+    resolve_to_bound.main();
     runtime_type_equality.main();
     subtype.main();
     top_merge.main();
diff --git a/pkg/analyzer/test/src/summary/macro/declaration_text.dart b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
index f438eec..265f230 100644
--- a/pkg/analyzer/test/src/summary/macro/declaration_text.dart
+++ b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
@@ -6,6 +6,8 @@
 
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
 
+import 'introspect_shared.dart';
+
 /*macro*/ class DeclarationTextMacro implements ClassTypesMacro {
   const DeclarationTextMacro();
 
@@ -88,15 +90,14 @@
     _sink.write('$name: ');
 
     if (type != null) {
-      _writeln(_typeStr(type));
+      _writeln(type.asString);
     } else {
       _writeln('null');
     }
   }
 
   void _writeTypeAnnotationLine(TypeAnnotation type) {
-    var typeStr = _typeStr(type);
-    _writelnWithIndent(typeStr);
+    _writelnWithIndent(type.asString);
   }
 
   void _writeTypeAnnotations(String name, Iterable<TypeAnnotation> elements) {
@@ -117,138 +118,4 @@
   void _writeTypeParameters(Iterable<TypeParameterDeclaration> elements) {
     _writeElements('typeParameters', elements, _writeTypeParameter);
   }
-
-  static String _typeStr(TypeAnnotation type) {
-    final buffer = StringBuffer();
-    _TypeStringBuilder(buffer).write(type);
-    return buffer.toString();
-  }
-}
-
-class _TypeStringBuilder {
-  final StringSink _sink;
-
-  _TypeStringBuilder(this._sink);
-
-  void write(TypeAnnotation type) {
-    if (type is FunctionTypeAnnotation) {
-      _writeFunctionTypeAnnotation(type);
-    } else if (type is NamedTypeAnnotation) {
-      _writeNamedTypeAnnotation(type);
-    } else if (type is OmittedTypeAnnotation) {
-      _sink.write('OmittedType');
-    } else {
-      throw UnimplementedError('(${type.runtimeType}) $type');
-    }
-    if (type.isNullable) {
-      _sink.write('?');
-    }
-  }
-
-  void _writeFormalParameter(FunctionTypeParameter node) {
-    final String closeSeparator;
-    if (node.isNamed) {
-      _sink.write('{');
-      closeSeparator = '}';
-      if (node.isRequired) {
-        _sink.write('required ');
-      }
-    } else if (!node.isRequired) {
-      _sink.write('[');
-      closeSeparator = ']';
-    } else {
-      closeSeparator = '';
-    }
-
-    write(node.type);
-    if (node.name != null) {
-      _sink.write(' ');
-      _sink.write(node.name);
-    }
-
-    _sink.write(closeSeparator);
-  }
-
-  void _writeFunctionTypeAnnotation(FunctionTypeAnnotation type) {
-    write(type.returnType);
-    _sink.write(' Function');
-
-    _sink.writeList(
-      elements: type.typeParameters,
-      write: _writeTypeParameter,
-      separator: ', ',
-      open: '<',
-      close: '>',
-    );
-
-    _sink.write('(');
-    var hasFormalParameter = false;
-    for (final formalParameter in type.positionalParameters) {
-      if (hasFormalParameter) {
-        _sink.write(', ');
-      }
-      _writeFormalParameter(formalParameter);
-      hasFormalParameter = true;
-    }
-    for (final formalParameter in type.namedParameters) {
-      if (hasFormalParameter) {
-        _sink.write(', ');
-      }
-      _writeFormalParameter(formalParameter);
-      hasFormalParameter = true;
-    }
-    _sink.write(')');
-  }
-
-  void _writeNamedTypeAnnotation(NamedTypeAnnotation type) {
-    _sink.write(type.identifier.name);
-    _sink.writeList(
-      elements: type.typeArguments,
-      write: write,
-      separator: ', ',
-      open: '<',
-      close: '>',
-    );
-  }
-
-  void _writeTypeParameter(TypeParameterDeclaration node) {
-    _sink.write(node.identifier.name);
-
-    final bound = node.bound;
-    if (bound != null) {
-      _sink.write(' extends ');
-      write(bound);
-    }
-  }
-}
-
-extension on StringSink {
-  void writeList<T>({
-    required Iterable<T> elements,
-    required void Function(T element) write,
-    required String separator,
-    String? open,
-    String? close,
-  }) {
-    elements = elements.toList();
-    if (elements.isEmpty) {
-      return;
-    }
-
-    if (open != null) {
-      this.write(open);
-    }
-    var isFirst = true;
-    for (var element in elements) {
-      if (isFirst) {
-        isFirst = false;
-      } else {
-        this.write(separator);
-      }
-      write(element);
-    }
-    if (close != null) {
-      this.write(close);
-    }
-  }
 }
diff --git a/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart b/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart
index 3a2515a..d5889ae 100644
--- a/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart
+++ b/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart
@@ -6,6 +6,8 @@
 
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
 
+import 'introspect_shared.dart';
+
 const introspectMacro = IntrospectDeclarationsPhaseMacro();
 
 /*macro*/ class IntrospectDeclarationsPhaseMacro
@@ -19,6 +21,7 @@
   ) async {
     final printer = _DeclarationPrinter(
       classIntrospector: builder,
+      typeResolver: builder,
     );
     await printer.writeClassDeclaration(declaration);
     final text = printer._sink.toString();
@@ -34,11 +37,13 @@
 
 class _DeclarationPrinter {
   final ClassIntrospector classIntrospector;
+  final TypeResolver typeResolver;
   final StringBuffer _sink = StringBuffer();
   String _indent = '';
 
   _DeclarationPrinter({
     required this.classIntrospector,
+    required this.typeResolver,
   });
 
   Future<void> writeClassDeclaration(ClassDeclaration e) async {
@@ -55,10 +60,9 @@
         await _withIndent(() => writeClassDeclaration(superclass));
       }
 
-      // TODO(scheglov) implement
-      // _writeTypeParameters(e.typeParameters);
-      // _writeTypeAnnotations('mixins', e.mixins);
-      // _writeTypeAnnotations('interfaces', e.interfaces);
+      await _writeTypeParameters(e.typeParameters);
+      await _writeTypeAnnotations('mixins', e.mixins);
+      await _writeTypeAnnotations('interfaces', e.interfaces);
     });
   }
 
@@ -69,6 +73,21 @@
     _indent = savedIndent;
   }
 
+  Future<void> _writeElements<T>(
+    String name,
+    Iterable<T> elements,
+    Future<void> Function(T) f,
+  ) async {
+    if (elements.isNotEmpty) {
+      _writelnWithIndent(name);
+      await _withIndent(() async {
+        for (var element in elements) {
+          await f(element);
+        }
+      });
+    }
+  }
+
   void _writeIf(bool flag, String str) {
     if (flag) {
       _sink.write(str);
@@ -83,4 +102,43 @@
     _sink.write(_indent);
     _sink.writeln(line);
   }
+
+  void _writeTypeAnnotation(String name, TypeAnnotation? type) {
+    _sink.write(_indent);
+    _sink.write('$name: ');
+
+    if (type != null) {
+      _writeln(type.asString);
+    } else {
+      _writeln('null');
+    }
+  }
+
+  Future<void> _writeTypeAnnotationLine(TypeAnnotation type) async {
+    _writelnWithIndent(type.asString);
+  }
+
+  Future<void> _writeTypeAnnotations(
+    String name,
+    Iterable<TypeAnnotation> elements,
+  ) async {
+    await _writeElements(name, elements, _writeTypeAnnotationLine);
+  }
+
+  Future<void> _writeTypeParameter(TypeParameterDeclaration e) async {
+    _writelnWithIndent(e.identifier.name);
+
+    await _withIndent(() async {
+      var bound = e.bound;
+      if (bound != null) {
+        _writeTypeAnnotation('bound', bound);
+      }
+    });
+  }
+
+  Future<void> _writeTypeParameters(
+    Iterable<TypeParameterDeclaration> elements,
+  ) async {
+    await _writeElements('typeParameters', elements, _writeTypeParameter);
+  }
 }
diff --git a/pkg/analyzer/test/src/summary/macro/introspect_shared.dart b/pkg/analyzer/test/src/summary/macro/introspect_shared.dart
new file mode 100644
index 0000000..b1c5b7f
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/macro/introspect_shared.dart
@@ -0,0 +1,141 @@
+// 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.
+
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+class _TypeAnnotationStringBuilder {
+  final StringSink _sink;
+
+  _TypeAnnotationStringBuilder(this._sink);
+
+  void write(TypeAnnotation type) {
+    if (type is FunctionTypeAnnotation) {
+      _writeFunctionTypeAnnotation(type);
+    } else if (type is NamedTypeAnnotation) {
+      _writeNamedTypeAnnotation(type);
+    } else if (type is OmittedTypeAnnotation) {
+      _sink.write('OmittedType');
+    } else {
+      throw UnimplementedError('(${type.runtimeType}) $type');
+    }
+    if (type.isNullable) {
+      _sink.write('?');
+    }
+  }
+
+  void _writeFormalParameter(FunctionTypeParameter node) {
+    final String closeSeparator;
+    if (node.isNamed) {
+      _sink.write('{');
+      closeSeparator = '}';
+      if (node.isRequired) {
+        _sink.write('required ');
+      }
+    } else if (!node.isRequired) {
+      _sink.write('[');
+      closeSeparator = ']';
+    } else {
+      closeSeparator = '';
+    }
+
+    write(node.type);
+    if (node.name != null) {
+      _sink.write(' ');
+      _sink.write(node.name);
+    }
+
+    _sink.write(closeSeparator);
+  }
+
+  void _writeFunctionTypeAnnotation(FunctionTypeAnnotation type) {
+    write(type.returnType);
+    _sink.write(' Function');
+
+    _sink.writeList(
+      elements: type.typeParameters,
+      write: _writeTypeParameter,
+      separator: ', ',
+      open: '<',
+      close: '>',
+    );
+
+    _sink.write('(');
+    var hasFormalParameter = false;
+    for (final formalParameter in type.positionalParameters) {
+      if (hasFormalParameter) {
+        _sink.write(', ');
+      }
+      _writeFormalParameter(formalParameter);
+      hasFormalParameter = true;
+    }
+    for (final formalParameter in type.namedParameters) {
+      if (hasFormalParameter) {
+        _sink.write(', ');
+      }
+      _writeFormalParameter(formalParameter);
+      hasFormalParameter = true;
+    }
+    _sink.write(')');
+  }
+
+  void _writeNamedTypeAnnotation(NamedTypeAnnotation type) {
+    _sink.write(type.identifier.name);
+    _sink.writeList(
+      elements: type.typeArguments,
+      write: write,
+      separator: ', ',
+      open: '<',
+      close: '>',
+    );
+  }
+
+  void _writeTypeParameter(TypeParameterDeclaration node) {
+    _sink.write(node.identifier.name);
+
+    final bound = node.bound;
+    if (bound != null) {
+      _sink.write(' extends ');
+      write(bound);
+    }
+  }
+}
+
+extension on StringSink {
+  void writeList<T>({
+    required Iterable<T> elements,
+    required void Function(T element) write,
+    required String separator,
+    String? open,
+    String? close,
+  }) {
+    elements = elements.toList();
+    if (elements.isEmpty) {
+      return;
+    }
+
+    if (open != null) {
+      this.write(open);
+    }
+    var isFirst = true;
+    for (var element in elements) {
+      if (isFirst) {
+        isFirst = false;
+      } else {
+        this.write(separator);
+      }
+      write(element);
+    }
+    if (close != null) {
+      this.write(close);
+    }
+  }
+}
+
+extension E on TypeAnnotation {
+  String get asString {
+    final buffer = StringBuffer();
+    _TypeAnnotationStringBuilder(buffer).write(this);
+    return buffer.toString();
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index a775b53..27d3339 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -65,6 +65,12 @@
     return code.replaceAll('/*macro*/', 'macro');
   }
 
+  String get _introspectSharedCode {
+    return MacrosEnvironment.instance.packageAnalyzerFolder
+        .getChildAssumingFile('test/src/summary/macro/introspect_shared.dart')
+        .readAsStringSync();
+  }
+
   Future<void> setUp() async {
     writeTestPackageConfig(
       PackageConfigFileBuilder(),
@@ -1152,6 +1158,133 @@
 ''');
   }
 
+  test_introspect_declarations_ClassDeclaration_imported_interfaces() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+class B {}
+class C implements A, B {}
+''');
+
+    await _assertIntrospectDeclarationsText(r'''
+import 'a.dart';
+
+@introspectMacro
+class X extends C {}
+''', r'''
+class X
+  superclass
+    class C
+      superclass
+        class Object
+      interfaces
+        A
+        B
+''');
+  }
+
+  test_introspect_declarations_ClassDeclaration_imported_isAbstract() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+abstract class A {}
+''');
+
+    await _assertIntrospectDeclarationsText(r'''
+import 'a.dart';
+
+@introspectMacro
+class X extends A {}
+''', r'''
+class X
+  superclass
+    abstract class A
+      superclass
+        class Object
+''');
+  }
+
+  test_introspect_declarations_ClassDeclaration_imported_mixins() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+mixin M1 {}
+mixin M2 {}
+class C with M1, M2 {}
+''');
+
+    await _assertIntrospectDeclarationsText(r'''
+import 'a.dart';
+
+@introspectMacro
+class X extends C {}
+''', r'''
+class X
+  superclass
+    class C
+      superclass
+        class Object
+      mixins
+        M1
+        M2
+''');
+  }
+
+  test_introspect_declarations_ClassDeclaration_imported_superclass() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+class B extends A {}
+''');
+
+    await _assertIntrospectDeclarationsText(r'''
+import 'a.dart';
+
+@introspectMacro
+class X extends B {}
+''', r'''
+class X
+  superclass
+    class B
+      superclass
+        class A
+          superclass
+            class Object
+''');
+  }
+
+  test_introspect_declarations_ClassDeclaration_imported_typeParameters() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A<T, U extends List<T>> {}
+''');
+
+    await _assertIntrospectDeclarationsText(r'''
+import 'a.dart';
+
+@introspectMacro
+class X extends A {}
+''', r'''
+class X
+  superclass
+    class A
+      superclass
+        class Object
+      typeParameters
+        T
+        U
+          bound: List<T>
+''');
+  }
+
+  test_introspect_declarations_ClassDeclaration_superclassOf() async {
+    await _assertIntrospectDeclarationsText(r'''
+class A {}
+
+@introspectMacro
+class X extends A {}
+''', r'''
+class X
+  superclass
+    class A
+      superclass
+        class Object
+''');
+  }
+
   test_introspect_declarations_ClassDeclaration_superclassOf_implicit() async {
     await _assertIntrospectDeclarationsText(r'''
 @introspectMacro
@@ -1163,18 +1296,14 @@
 ''');
   }
 
-  test_introspect_declarations_ClassDeclaration_superclassOf_local() async {
+  test_introspect_declarations_ClassDeclaration_superclassOf_unresolved() async {
     await _assertIntrospectDeclarationsText(r'''
-class A<T> {}
-
 @introspectMacro
-class X extends A<int> {}
+class X extends A {}
 ''', r'''
 class X
   superclass
-    class A
-      superclass
-        class Object
+    class Object
 ''');
   }
 
@@ -1598,6 +1727,11 @@
   /// declaration.
   Future<String> _getDeclarationText(String declarationCode) async {
     newFile(
+      '$testPackageLibPath/introspect_shared.dart',
+      _introspectSharedCode,
+    );
+
+    newFile(
       '$testPackageLibPath/declaration_text.dart',
       _declarationTextCode,
     );
@@ -1608,7 +1742,10 @@
 @DeclarationTextMacro()
 $declarationCode
 ''', preBuildSequence: [
-      {'package:test/declaration_text.dart'}
+      {
+        'package:test/introspect_shared.dart',
+        'package:test/declaration_text.dart',
+      }
     ]);
 
     _assertNoErrorsForClassElement(
@@ -1627,16 +1764,23 @@
   /// macro annotated declarations.
   Future<String> _getIntrospectDeclarationsText(String declarationCode) async {
     newFile(
+      '$testPackageLibPath/introspect_shared.dart',
+      _introspectSharedCode,
+    );
+
+    newFile(
       '$testPackageLibPath/introspect_declarations_phase.dart',
       _introspectDeclarationsPhaseCode,
     );
 
     var library = await buildLibrary('''
 import 'introspect_declarations_phase.dart';
-
 $declarationCode
 ''', preBuildSequence: [
-      {'package:test/introspect_declarations_phase.dart'}
+      {
+        'package:test/introspect_shared.dart',
+        'package:test/introspect_declarations_phase.dart',
+      }
     ]);
 
     for (final class_ in library.definingCompilationUnit.classes) {
diff --git a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
index 1f5e31b..1a578bb 100644
--- a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
@@ -11,7 +11,9 @@
 class _FunctionData {
   final List<AwaitExpression> awaits = [];
   final Set<ReturnStatement> returnStatements = {};
-  bool hasAsyncLoop = false;
+  // If we find certain control flow statements in this function, we choose to
+  // not lower it.
+  bool shouldLower = true;
 
   _FunctionData();
 
@@ -35,7 +37,9 @@
   AsyncLowering(this._coreTypes);
 
   bool _shouldTryAsyncLowering(FunctionNode node) =>
-      node.asyncMarker == AsyncMarker.Async && !_functions.last.hasAsyncLoop;
+      node.asyncMarker == AsyncMarker.Async &&
+      node.futureValueType != null &&
+      _functions.last.shouldLower;
 
   void enterFunction(FunctionNode node) {
     _functions.add(_FunctionData());
@@ -66,6 +70,20 @@
             ]))));
   }
 
+  void _wrapReturns(_FunctionData functionData, FunctionNode node) {
+    final futureValueType = node.futureValueType!;
+    for (final returnStatement in functionData.returnStatements) {
+      final expression = returnStatement.expression;
+      // Ensure the returned future has a runtime type (T) matching the
+      // function's return type by wrapping with Future.value<T>.
+      if (expression == null) continue;
+      final futureValueCall = StaticInvocation(_coreTypes.futureValueFactory,
+          Arguments([expression], types: [futureValueType]));
+      returnStatement.expression = futureValueCall;
+      futureValueCall.parent = returnStatement;
+    }
+  }
+
   void _transformDirectReturnAwaits(
       FunctionNode node, _FunctionData functionData) {
     // If every await is the direct child of a return statement then we can
@@ -117,6 +135,7 @@
       isLowered = true;
     }
     if (isLowered) {
+      _wrapReturns(functionData, node);
       _wrapBodySync(node);
     }
   }
@@ -138,7 +157,11 @@
 
   void visitForInStatement(ForInStatement statement) {
     if (statement.isAsync && _functions.isNotEmpty) {
-      _functions.last.hasAsyncLoop = true;
+      _functions.last.shouldLower = false;
     }
   }
+
+  void visitTry() {
+    _functions.last.shouldLower = false;
+  }
 }
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
index b90f526..9490c32 100644
--- a/pkg/compiler/lib/src/kernel/transformations/lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
@@ -114,4 +114,18 @@
     statement.transformChildren(this);
     return statement;
   }
+
+  @override
+  TreeNode visitTryFinally(TryFinally statement) {
+    _asyncLowering?.visitTry();
+    statement.transformChildren(this);
+    return statement;
+  }
+
+  @override
+  TreeNode visitTryCatch(TryCatch statement) {
+    _asyncLowering?.visitTry();
+    statement.transformChildren(this);
+    return statement;
+  }
 }
diff --git a/pkg/compiler/lib/src/serialization/binary_sink.dart b/pkg/compiler/lib/src/serialization/binary_sink.dart
index c5c52a7..c408ccc 100644
--- a/pkg/compiler/lib/src/serialization/binary_sink.dart
+++ b/pkg/compiler/lib/src/serialization/binary_sink.dart
@@ -2,16 +2,17 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.10
-
-part of 'serialization.dart';
+import 'dart:convert';
+import 'package:kernel/binary/ast_to_binary.dart';
+import 'data_sink.dart';
 
 /// [DataSink] that writes data as a sequence of bytes.
 ///
 /// This data sink works together with [BinarySourceWriter].
 class BinaryDataSink implements DataSink {
   final Sink<List<int>> sink;
-  BufferedSink _bufferedSink;
+  // Nullable and non-final to allow storage to be released.
+  BufferedSink? _bufferedSink;
   int _length = 0;
 
   BinaryDataSink(this.sink) : _bufferedSink = BufferedSink(sink);
@@ -33,7 +34,7 @@
   void writeString(String value) {
     List<int> bytes = utf8.encode(value);
     writeInt(bytes.length);
-    _bufferedSink.addBytes(bytes);
+    _bufferedSink!.addBytes(bytes);
     _length += bytes.length;
   }
 
@@ -41,13 +42,13 @@
   void writeInt(int value) {
     assert(value >= 0 && value >> 30 == 0);
     if (value < 0x80) {
-      _bufferedSink.addByte(value);
+      _bufferedSink!.addByte(value);
       _length += 1;
     } else if (value < 0x4000) {
-      _bufferedSink.addByte2((value >> 8) | 0x80, value & 0xFF);
+      _bufferedSink!.addByte2((value >> 8) | 0x80, value & 0xFF);
       _length += 2;
     } else {
-      _bufferedSink.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF,
+      _bufferedSink!.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF,
           (value >> 8) & 0xFF, value & 0xFF);
       _length += 4;
     }
@@ -60,7 +61,7 @@
 
   @override
   void close() {
-    _bufferedSink.flushAndDestroy();
+    _bufferedSink!.flushAndDestroy();
     _bufferedSink = null;
     sink.close();
   }
diff --git a/pkg/compiler/lib/src/serialization/binary_source.dart b/pkg/compiler/lib/src/serialization/binary_source.dart
index 00d1291..59f40ff 100644
--- a/pkg/compiler/lib/src/serialization/binary_source.dart
+++ b/pkg/compiler/lib/src/serialization/binary_source.dart
@@ -2,9 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.10
-
-part of 'serialization.dart';
+import 'dart:convert';
+import 'dart:typed_data';
+import 'data_source.dart';
+import 'serialization_interfaces.dart' show StringInterner;
 
 /// [DataSource] that reads data from a sequence of bytes.
 ///
@@ -12,10 +13,12 @@
 class BinaryDataSource implements DataSource {
   int _byteOffset = 0;
   final List<int> _bytes;
-  final StringInterner _stringInterner;
+  final StringInterner? _stringInterner;
 
-  BinaryDataSource(this._bytes, {StringInterner stringInterner})
-      : _stringInterner = stringInterner;
+  BinaryDataSource(this._bytes, {StringInterner? stringInterner})
+      : _stringInterner = stringInterner {
+    assert((_bytes as dynamic) != null); // TODO(48820): Remove when sound.
+  }
 
   @override
   void begin(String tag) {}
@@ -33,7 +36,7 @@
     _byteOffset += bytes.length;
     String string = utf8.decode(bytes);
     if (_stringInterner == null) return string;
-    return _stringInterner.internString(string);
+    return _stringInterner!.internString(string);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/serialization/data_sink.dart b/pkg/compiler/lib/src/serialization/data_sink.dart
new file mode 100644
index 0000000..b87ebcd
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/data_sink.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2018, 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.
+
+/// Interface handling [DataSinkWriter] low-level data serialization.
+///
+/// Each implementation of [DataSink] should have a corresponding
+/// [DataSource] that deserializes data serialized by that implementation.
+// TODO(48820): Move this interface back to 'sink.dart'.
+abstract class DataSink {
+  int get length;
+
+  /// Serialization of a non-negative integer value.
+  void writeInt(int value);
+
+  /// Serialization of an enum value.
+  void writeEnum(dynamic value);
+
+  /// Serialization of a String value.
+  void writeString(String value);
+
+  /// Serialization of a section begin tag. May be omitted by some writers.
+  void beginTag(String tag);
+
+  /// Serialization of a section end tag. May be omitted by some writers.
+  void endTag(String tag);
+
+  /// Closes any underlying data sinks.
+  void close();
+}
diff --git a/pkg/compiler/lib/src/serialization/data_source.dart b/pkg/compiler/lib/src/serialization/data_source.dart
new file mode 100644
index 0000000..ee73699
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/data_source.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2018, 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.
+
+/// Interface handling [DataSourceReader] low-level data deserialization.
+///
+/// Each implementation of [DataSource] should have a corresponding
+/// [DataSink] for which it deserializes data.
+abstract class DataSource {
+  /// Deserialization of a section begin tag.
+  void begin(String tag);
+
+  /// Deserialization of a section end tag.
+  void end(String tag);
+
+  /// Deserialization of a string value.
+  String readString();
+
+  /// Deserialization of a non-negative integer value.
+  int readInt();
+
+  /// Deserialization of an enum value in [values].
+  E readEnum<E>(List<E> values);
+
+  /// Returns a string representation of the current state of the data source
+  /// useful for debugging in consistencies between serialization and
+  /// deserialization.
+  String get errorContext;
+}
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index 51e28e1..46791ba 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -166,66 +166,3 @@
     visitTypes(node.typeArguments, functionTypeVariables);
   }
 }
-
-/// Data sink helper that canonicalizes [E] values using indices.
-class IndexedSink<E> {
-  final DataSink _sink;
-  Map<E, int> cache;
-
-  IndexedSink(this._sink, {this.cache}) {
-    // [cache] slot 0 is pre-allocated to `null`.
-    this.cache ??= {null: 0};
-  }
-
-  /// Write a reference to [value] to the data sink.
-  ///
-  /// If [value] has not been canonicalized yet, [writeValue] is called to
-  /// serialize the [value] itself.
-  void write(E value, void writeValue(E value)) {
-    const int pending = -1;
-    int index = cache[value];
-    if (index == null) {
-      index = cache.length;
-      _sink.writeInt(index);
-      cache[value] = pending; // Increments length to allocate slot.
-      writeValue(value);
-      cache[value] = index;
-    } else if (index == pending) {
-      throw ArgumentError("Cyclic dependency on cached value: $value");
-    } else {
-      _sink.writeInt(index);
-    }
-  }
-}
-
-/// Data source helper reads canonicalized [E] values through indices.
-class IndexedSource<E> {
-  final DataSource _sourceReader;
-  List<E> cache;
-
-  IndexedSource(this._sourceReader, {this.cache}) {
-    // [cache] slot 0 is pre-allocated to `null`.
-    this.cache ??= [null];
-  }
-
-  /// Reads a reference to an [E] value from the data source.
-  ///
-  /// If the value hasn't yet been read, [readValue] is called to deserialize
-  /// the value itself.
-  E read(E readValue()) {
-    int index = _sourceReader.readInt();
-    if (index >= cache.length) {
-      assert(index == cache.length);
-      cache.add(null); // placeholder.
-      E value = readValue();
-      cache[index] = value;
-      return value;
-    } else {
-      E value = cache[index];
-      if (value == null && index != 0) {
-        throw StateError('Unfilled index $index of $E');
-      }
-      return value;
-    }
-  }
-}
diff --git a/pkg/compiler/lib/src/serialization/indexed_sink_source.dart b/pkg/compiler/lib/src/serialization/indexed_sink_source.dart
new file mode 100644
index 0000000..82db5e0
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/indexed_sink_source.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2018, 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 'data_sink.dart';
+import 'data_source.dart';
+
+/// Data sink helper that canonicalizes [E?] values using indices.
+class IndexedSink<E extends Object> {
+  final DataSink _sink;
+  final Map<E?, int> cache;
+
+  IndexedSink._(this._sink, this.cache);
+
+  factory IndexedSink(DataSink sink, {Map<E?, int>? cache}) {
+    // [cache] slot 0 is pre-allocated to `null`.
+    cache ??= {null: 0};
+    return IndexedSink._(sink, cache);
+  }
+
+  /// Write a reference to [value] to the data sink.
+  ///
+  /// If [value] has not been canonicalized yet, [writeValue] is called to
+  /// serialize the [value] itself.
+  void write(E? value, void writeValue(E value)) {
+    const int pending = -1;
+    int? index = cache[value];
+    if (index == null) {
+      index = cache.length;
+      _sink.writeInt(index);
+      cache[value] = pending; // Increments length to allocate slot.
+      writeValue(value!); // `null` would have been found in slot 0.
+      cache[value] = index;
+    } else if (index == pending) {
+      throw ArgumentError("Cyclic dependency on cached value: $value");
+    } else {
+      _sink.writeInt(index);
+    }
+  }
+}
+
+/// Data source helper reads canonicalized [E?] values through indices.
+class IndexedSource<E extends Object> {
+  final DataSource _source;
+  final List<E?> cache;
+
+  IndexedSource._(this._source, this.cache);
+
+  factory IndexedSource(DataSource source, {List<E?>? cache}) {
+    // [cache] slot 0 is pre-allocated to `null`.
+    cache ??= [null];
+    return IndexedSource._(source, cache);
+  }
+
+  /// Reads a reference to an [E] value from the data source.
+  ///
+  /// If the value hasn't yet been read, [readValue] is called to deserialize
+  /// the value itself.
+  E? read(E readValue()) {
+    int index = _source.readInt();
+    if (index >= cache.length) {
+      assert(index == cache.length);
+      cache.add(null); // placeholder.
+      E value = readValue();
+      cache[index] = value;
+      return value;
+    } else {
+      E? value = cache[index];
+      if (value == null && index != 0) {
+        throw StateError('Unfilled index $index of $E');
+      }
+      return value;
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/serialization/object_sink.dart b/pkg/compiler/lib/src/serialization/object_sink.dart
index d5b54b4..3bbbd3b 100644
--- a/pkg/compiler/lib/src/serialization/object_sink.dart
+++ b/pkg/compiler/lib/src/serialization/object_sink.dart
@@ -2,45 +2,45 @@
 // 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
-
-part of 'serialization.dart';
+import 'data_sink.dart';
+import 'tags.dart' show Tag;
 
 /// [DataSinkWriter] that writes to a list of objects, useful for debugging
 /// inconsistencies between serialization and deserialization.
 ///
 /// This data sink writer works together with [ObjectDataSource].
 class ObjectDataSink implements DataSink {
-  List<dynamic> _data;
+  // [_data] is nullable and non-final to allow storage to be released.
+  List<dynamic>? _data;
 
   ObjectDataSink(this._data);
 
   @override
   void beginTag(String tag) {
-    _data.add(Tag('begin:$tag'));
+    _data!.add(Tag('begin:$tag'));
   }
 
   @override
   void endTag(String tag) {
-    _data.add(Tag('end:$tag'));
+    _data!.add(Tag('end:$tag'));
   }
 
   @override
   void writeEnum(dynamic value) {
-    assert(value != null);
-    _data.add(value);
+    assert((value as dynamic) != null); // TODO(48820): Remove when sound.
+    _data!.add(value);
   }
 
   @override
   void writeInt(int value) {
-    assert(value != null);
-    _data.add(value);
+    assert((value as dynamic) != null); // TODO(48820): Remove when sound.
+    _data!.add(value);
   }
 
   @override
   void writeString(String value) {
-    assert(value != null);
-    _data.add(value);
+    assert((value as dynamic) != null); // TODO(48820): Remove when sound.
+    _data!.add(value);
   }
 
   @override
@@ -50,5 +50,5 @@
 
   /// Returns the number of objects written to this data sink.
   @override
-  int get length => _data.length;
+  int get length => _data!.length;
 }
diff --git a/pkg/compiler/lib/src/serialization/object_source.dart b/pkg/compiler/lib/src/serialization/object_source.dart
index bc34994..f8279a2 100644
--- a/pkg/compiler/lib/src/serialization/object_source.dart
+++ b/pkg/compiler/lib/src/serialization/object_source.dart
@@ -2,9 +2,8 @@
 // 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
-
-part of 'serialization.dart';
+import 'data_source.dart';
+import 'tags.dart' show Tag;
 
 /// [DataSource] that read from a list of objects, useful for debugging
 /// inconsistencies between serialization and deserialization.
@@ -17,9 +16,9 @@
   ObjectDataSource(this._data);
 
   T _read<T>() {
-    dynamic value = _data[_index++];
-    assert(value is T, "Expected $T value, found $value.$errorContext");
-    return value;
+    Object? value = _data[_index++];
+    if (value is T) return value;
+    throw StateError('Expected $T value, found $value.$errorContext');
   }
 
   @override
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index a863d05..d0aa69e 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -5,10 +5,8 @@
 // @dart = 2.10
 
 import 'dart:collection';
-import 'dart:convert';
 import 'dart:typed_data';
 import 'package:kernel/ast.dart' as ir;
-import 'package:kernel/binary/ast_to_binary.dart';
 import '../closure.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
@@ -25,24 +23,24 @@
 import '../js_model/locals.dart';
 import '../js_model/type_recipe.dart' show TypeRecipe;
 
+import 'data_sink.dart';
+import 'data_source.dart';
 import 'member_data.dart';
-export 'member_data.dart' show ComponentLookup, computeMemberName;
 import 'serialization_interfaces.dart' as migrated
     show DataSourceReader, DataSinkWriter;
+import 'indexed_sink_source.dart';
 import 'tags.dart';
+
+export 'binary_sink.dart';
+export 'binary_source.dart';
+export 'member_data.dart' show ComponentLookup, computeMemberName;
+export 'object_sink.dart';
+export 'object_source.dart';
 export 'tags.dart';
 
 part 'sink.dart';
 part 'source.dart';
-part 'binary_sink.dart';
-part 'binary_source.dart';
 part 'helpers.dart';
-part 'object_sink.dart';
-part 'object_source.dart';
-
-abstract class StringInterner {
-  String internString(String string);
-}
 
 class ValueInterner {
   final Map<DartType, DartType> _dartTypeMap = HashMap();
diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
index a2ee9dd..efa9bb1 100644
--- a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
@@ -9,6 +9,10 @@
 
 export 'tags.dart';
 
+abstract class StringInterner {
+  String internString(String string);
+}
+
 /// NNBD-migrated interface for methods of DataSinkWriter.
 ///
 /// This is a pure interface or facade for DataSinkWriter.
@@ -73,6 +77,7 @@
       {bool allowNull = false});
 
   void writeCached<E extends Object>(E value, void f(E value));
+
   void writeList<E extends Object>(Iterable<E> values, void f(E value),
       {bool allowNull = false});
 }
@@ -112,6 +117,7 @@
   Map<K, V>? readTreeNodeMapInContextOrNull<K extends ir.TreeNode, V>(V f());
 
   E readCached<E extends Object>(E f());
+
   List<E> readList<E extends Object>(E f());
   List<E>? readListOrNull<E extends Object>(E f());
 }
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart
index 67ec6b5..214b6e9 100644
--- a/pkg/compiler/lib/src/serialization/sink.dart
+++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -6,32 +6,6 @@
 
 part of 'serialization.dart';
 
-/// Interface handling [DataSinkWriter] low-level data serialization.
-///
-/// Each implementation of [DataSink] should have a corresponding
-/// [DataSource] that deserializes data serialized by that implementation.
-abstract class DataSink {
-  int get length;
-
-  /// Serialization of a non-negative integer value.
-  void writeInt(int value);
-
-  /// Serialization of an enum value.
-  void writeEnum(dynamic value);
-
-  /// Serialization of a String value.
-  void writeString(String value);
-
-  /// Serialization of a section begin tag. May be omitted by some writers.
-  void beginTag(String tag);
-
-  /// Serialization of a section end tag. May be omitted by some writers.
-  void endTag(String tag);
-
-  /// Closes any underlying data sinks.
-  void close();
-}
-
 /// Serialization writer
 ///
 /// To be used with [DataSourceReader] to read and write serialized data.
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index 806731c..2d0855c 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -6,32 +6,6 @@
 
 part of 'serialization.dart';
 
-/// Interface handling [DataSourceReader] low-level data deserialization.
-///
-/// Each implementation of [DataSource] should have a corresponding
-/// [DataSink] for which it deserializes data.
-abstract class DataSource {
-  /// Deserialization of a section begin tag.
-  void begin(String tag);
-
-  /// Deserialization of a section end tag.
-  void end(String tag);
-
-  /// Deserialization of a string value.
-  String readString();
-
-  /// Deserialization of a non-negative integer value.
-  int readInt();
-
-  /// Deserialization of an enum value in [values].
-  E readEnum<E>(List<E> values);
-
-  /// Returns a string representation of the current state of the data source
-  /// useful for debugging in consistencies between serialization and
-  /// deserialization.
-  String get errorContext;
-}
-
 /// Deserialization reader
 ///
 /// To be used with [DataSinkWriter] to read and write serialized data.
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 6f9d2c4..b4e8b0b 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -29,6 +29,7 @@
 import '../util/sink_adapter.dart';
 import '../world.dart';
 import 'serialization.dart';
+import 'serialization_interfaces.dart' show StringInterner;
 
 /// A data class holding a [JsClosedWorld] and the associated
 /// [DataSourceIndices].
diff --git a/pkg/dev_compiler/lib/src/compiler/module_containers.dart b/pkg/dev_compiler/lib/src/compiler/module_containers.dart
index 8e954be..8150de59 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_containers.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_containers.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.9
-
 import '../compiler/js_names.dart' as js_ast;
 import '../js_ast/js_ast.dart' as js_ast;
 import '../js_ast/js_ast.dart' show js;
@@ -78,7 +76,7 @@
 
   /// Creates an automatically sharding container backed by JS Objects.
   factory ModuleItemContainer.asObject(String name,
-      {String Function(K) keyToString}) {
+      {required String Function(K) keyToString}) {
     return ModuleItemObjectContainer<K>(name, keyToString);
   }
 
@@ -95,7 +93,7 @@
 
   bool get isEmpty => moduleItems.isEmpty;
 
-  js_ast.Expression operator [](K key) => moduleItems[key]?.jsValue;
+  js_ast.Expression? operator [](K key) => moduleItems[key]?.jsValue;
 
   void operator []=(K key, js_ast.Expression value);
 
@@ -125,7 +123,7 @@
   /// necessary.
   ///
   /// Uses [emitValue] to emit the values in the table.
-  List<js_ast.Statement> emit({EmitValue<K> emitValue});
+  List<js_ast.Statement> emit({EmitValue<K>? emitValue});
 }
 
 /// Associates a [K] with a container-unique JS key and arbitrary JS value.
@@ -157,7 +155,7 @@
   @override
   void operator []=(K key, js_ast.Expression value) {
     if (contains(key)) {
-      moduleItems[key].jsValue = value;
+      moduleItems[key]!.jsValue = value;
       return;
     }
     // Create a unique name for K when emitted as a JS field.
@@ -179,12 +177,12 @@
 
   @override
   js_ast.Expression access(K key) {
-    var id = moduleItems[key].id;
-    return js.call('#.#', [id, moduleItems[key].jsKey]);
+    var id = moduleItems[key]!.id;
+    return js.call('#.#', [id, moduleItems[key]!.jsKey]);
   }
 
   @override
-  List<js_ast.Statement> emit({EmitValue<K> emitValue}) {
+  List<js_ast.Statement> emit({EmitValue<K>? emitValue}) {
     var containersToProperties = <js_ast.Identifier, List<js_ast.Property>>{};
     moduleItems.forEach((k, v) {
       if (!incrementalMode && _noEmit.contains(k)) return;
@@ -193,7 +191,7 @@
       if (!containersToProperties.containsKey(v.id)) {
         containersToProperties[v.id] = <js_ast.Property>[];
       }
-      containersToProperties[v.id].add(js_ast.Property(
+      containersToProperties[v.id]!.add(js_ast.Property(
           v.jsKey, emitValue == null ? v.jsValue : emitValue(k, v)));
     });
 
@@ -226,7 +224,7 @@
   @override
   void operator []=(K key, js_ast.Expression value) {
     if (moduleItems.containsKey(key)) {
-      moduleItems[key].jsValue = value;
+      moduleItems[key]!.jsValue = value;
       return;
     }
     moduleItems[key] =
@@ -236,12 +234,13 @@
   @override
   js_ast.Expression access(K key) {
     var id = containerId;
-    return js.call('#[#]', [id, moduleItems[key].jsKey]);
+    return js.call('#[#]', [id, moduleItems[key]!.jsKey]);
   }
 
   @override
-  List<js_ast.Statement> emit({EmitValue<K> emitValue}) {
-    var properties = List<js_ast.Expression>.filled(length, null);
+  List<js_ast.Statement> emit({EmitValue<K>? emitValue}) {
+    var dummyExpression = js_ast.TemporaryId('dummyExpression');
+    var properties = List<js_ast.Expression>.filled(length, dummyExpression);
 
     // If the entire array holds just one value, generate a short initializer.
     var valueSet = <js_ast.Expression>{};
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect
index 0e794df..7c9bb06 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect
@@ -8,19 +8,19 @@
 }
 static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
-    return self::bar();
+    return asy::Future::value<core::int>(self::bar());
   });
 static method foo2(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     if(x)
-      return asy::Future::value<core::int>(345);
-    return self::bar();
+      return asy::Future::value<core::int>(asy::Future::value<core::int>(345));
+    return asy::Future::value<core::int>(self::bar());
   });
 static method foo3(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     if(x)
-      return 234;
-    return asy::Future::value<core::int>(123);
+      return asy::Future::value<core::int>(234);
+    return asy::Future::value<core::int>(asy::Future::value<core::int>(123));
   });
 static method main() → void {
   self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect
index 0e794df..7c9bb06 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect
@@ -8,19 +8,19 @@
 }
 static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
-    return self::bar();
+    return asy::Future::value<core::int>(self::bar());
   });
 static method foo2(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     if(x)
-      return asy::Future::value<core::int>(345);
-    return self::bar();
+      return asy::Future::value<core::int>(asy::Future::value<core::int>(345));
+    return asy::Future::value<core::int>(self::bar());
   });
 static method foo3(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     if(x)
-      return 234;
-    return asy::Future::value<core::int>(123);
+      return asy::Future::value<core::int>(234);
+    return asy::Future::value<core::int>(asy::Future::value<core::int>(123));
   });
 static method main() → void {
   self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect
index 63a5d71..d926489 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect
@@ -6,7 +6,7 @@
 static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     final core::int c = 3;
-    return c;
+    return asy::Future::value<core::int>(c);
   });
 static method foo2() → asy::Future<void> /* futureValueType= void */ /* originally async */ 
   return asy::Future::sync<void>(() → FutureOr<void>? {
@@ -14,21 +14,21 @@
   });
 static method foo3() → dynamic /* futureValueType= dynamic */ /* originally async */ 
   return asy::Future::sync<dynamic>(() → FutureOr<dynamic>? {
-    return 234;
+    return asy::Future::value<dynamic>(234);
   });
 static method bar(() → asy::Future<core::int> func) → void {
   func(){() → asy::Future<core::int>};
 }
 static method foo4() → asy::Future<core::bool> async /* futureValueType= core::bool */ {
   await asy::Future::value<core::int>(2);
-  self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => 3));
+  self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => asy::Future::value<core::int>(3)));
   return true;
 }
 static method foo5(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     if(x)
-      return 123;
-    return 234;
+      return asy::Future::value<core::int>(123);
+    return asy::Future::value<core::int>(234);
   });
 static method main() → void {
   self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect
index 63a5d71..d926489 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect
@@ -6,7 +6,7 @@
 static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     final core::int c = 3;
-    return c;
+    return asy::Future::value<core::int>(c);
   });
 static method foo2() → asy::Future<void> /* futureValueType= void */ /* originally async */ 
   return asy::Future::sync<void>(() → FutureOr<void>? {
@@ -14,21 +14,21 @@
   });
 static method foo3() → dynamic /* futureValueType= dynamic */ /* originally async */ 
   return asy::Future::sync<dynamic>(() → FutureOr<dynamic>? {
-    return 234;
+    return asy::Future::value<dynamic>(234);
   });
 static method bar(() → asy::Future<core::int> func) → void {
   func(){() → asy::Future<core::int>};
 }
 static method foo4() → asy::Future<core::bool> async /* futureValueType= core::bool */ {
   await asy::Future::value<core::int>(2);
-  self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => 3));
+  self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => asy::Future::value<core::int>(3)));
   return true;
 }
 static method foo5(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ 
   return asy::Future::sync<core::int>(() → FutureOr<core::int> {
     if(x)
-      return 123;
-    return 234;
+      return asy::Future::value<core::int>(123);
+    return asy::Future::value<core::int>(234);
   });
 static method main() → void {
   self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
index e19523f..3e885ac 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
@@ -8,14 +8,35 @@
   return (await 6) + 3;
 }
 
+// Function contains an async for-in loop.
 Future<void> foo3() async {
   await for (final x in Stream.empty()) {
     break;
   }
 }
 
+// Function contains a try-finally statement.
+Future<int> foo4() async {
+  try {
+    return 3;
+  } finally {
+    return 2;
+  }
+}
+
+// Function contains a try-catch statement.
+Future<int> foo5() async {
+  try {
+    return 3;
+  } catch (e) {
+    return 2;
+  }
+}
+
 void main() {
   foo1();
   foo2();
   foo3();
+  foo4();
+  foo5();
 }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
index f3422b1..f6a9d58 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
@@ -15,8 +15,26 @@
     break #L1;
   }
 }
+static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  finally {
+    return 2;
+  }
+}
+static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  on core::Object catch(final core::Object e) {
+    return 2;
+  }
+}
 static method main() → void {
   self::foo1();
   self::foo2();
   self::foo3();
+  self::foo4();
+  self::foo5();
 }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
index f3422b1..f6a9d58 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
@@ -15,8 +15,26 @@
     break #L1;
   }
 }
+static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  finally {
+    return 2;
+  }
+}
+static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  on core::Object catch(final core::Object e) {
+    return 2;
+  }
+}
 static method main() → void {
   self::foo1();
   self::foo2();
   self::foo3();
+  self::foo4();
+  self::foo5();
 }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
index c9ebdd9..85cdbd2 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
@@ -1,4 +1,6 @@
 Future<void> foo1() async {}
 Future<int> foo2() async {}
 Future<void> foo3() async {}
+Future<int> foo4() async {}
+Future<int> foo5() async {}
 void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
index 4ab2b8a..51fc18a 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
@@ -1,4 +1,6 @@
 Future<int> foo2() async {}
+Future<int> foo4() async {}
+Future<int> foo5() async {}
 Future<void> foo1() async {}
 Future<void> foo3() async {}
 void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
index f3422b1..f6a9d58 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
@@ -15,8 +15,26 @@
     break #L1;
   }
 }
+static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  finally {
+    return 2;
+  }
+}
+static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  on core::Object catch(final core::Object e) {
+    return 2;
+  }
+}
 static method main() → void {
   self::foo1();
   self::foo2();
   self::foo3();
+  self::foo4();
+  self::foo5();
 }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
index f3422b1..f6a9d58 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
@@ -15,8 +15,26 @@
     break #L1;
   }
 }
+static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  finally {
+    return 2;
+  }
+}
+static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  on core::Object catch(final core::Object e) {
+    return 2;
+  }
+}
 static method main() → void {
   self::foo1();
   self::foo2();
   self::foo3();
+  self::foo4();
+  self::foo5();
 }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
index 0c508d4..389e9c1 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
@@ -9,5 +9,9 @@
   ;
 static method foo3() → asy::Future<void> async 
   ;
+static method foo4() → asy::Future<core::int> async 
+  ;
+static method foo5() → asy::Future<core::int> async 
+  ;
 static method main() → void
   ;
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
index f3422b1..f6a9d58 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
@@ -15,8 +15,26 @@
     break #L1;
   }
 }
+static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  finally {
+    return 2;
+  }
+}
+static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ {
+  try {
+    return 3;
+  }
+  on core::Object catch(final core::Object e) {
+    return 2;
+  }
+}
 static method main() → void {
   self::foo1();
   self::foo2();
   self::foo3();
+  self::foo4();
+  self::foo5();
 }
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 4b5adb2..70edb2c 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -181,6 +181,9 @@
   late final Procedure futureSyncFactory =
       index.getMember('dart:async', 'Future', 'sync') as Procedure;
 
+  late final Procedure futureValueFactory =
+      index.getMember('dart:async', 'Future', 'value') as Procedure;
+
   // TODO(cstefantsova): Remove it when FutureOrType is fully supported.
   late final Class deprecatedFutureOrClass =
       index.getClass('dart:async', 'FutureOr');
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 013e482..d6bfd32 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/dart/element/type_system.dart';
@@ -280,8 +281,7 @@
     if (targetType != null) {
       var enclosingElement = baseElement!.enclosingElement;
       if (enclosingElement is ClassElement) {
-        if (targetType.type!.resolveToBound(typeProvider.dynamicType)
-                is InterfaceType &&
+        if (targetType.type.explicitBound is InterfaceType &&
             enclosingElement.typeParameters.isNotEmpty) {
           substitution = _decoratedClassHierarchy!
               .asInstanceOf(targetType, enclosingElement)
@@ -3971,3 +3971,14 @@
       trueDemonstratesNonNullIntent: falseDemonstratesNonNullIntent,
       falseDemonstratesNonNullIntent: trueDemonstratesNonNullIntent);
 }
+
+extension on DartType? {
+  DartType? get explicitBound {
+    final self = this;
+    if (self is TypeParameterType &&
+        self.nullabilitySuffix == NullabilitySuffix.star) {
+      return self.element.bound.explicitBound;
+    }
+    return self;
+  }
+}
diff --git a/pkg/test_runner/lib/src/browser_controller.dart b/pkg/test_runner/lib/src/browser_controller.dart
index d785338..a6c8b8a 100644
--- a/pkg/test_runner/lib/src/browser_controller.dart
+++ b/pkg/test_runner/lib/src/browser_controller.dart
@@ -12,6 +12,7 @@
 import 'android.dart';
 import 'configuration.dart';
 import 'path.dart';
+import 'service/web_driver_service.dart';
 import 'utils.dart';
 
 typedef BrowserDoneCallback = void Function(BrowserTestOutput output);
@@ -75,7 +76,8 @@
         browser = Chrome(configuration.browserLocation);
         break;
       case Runtime.safari:
-        browser = Safari();
+        var service = WebDriverService.fromRuntime(Runtime.safari);
+        browser = Safari(service.port);
         break;
       case Runtime.ie9:
       case Runtime.ie10:
@@ -262,20 +264,15 @@
 
 abstract class WebDriverBrowser extends Browser {
   WebDriver _driver;
+  final int _port;
+  final Map<String, dynamic> _desiredCapabilities;
 
-  String get driverExecutable;
-  List<String> get driverArguments;
-  Map<String, dynamic> get desiredCapabilities;
+  WebDriverBrowser(this._port, this._desiredCapabilities);
 
   @override
   Future<bool> start(String url) async {
     _logEvent('Starting $this browser on: $url');
-    var port = await _findUnusedPort();
-    if (!await startBrowserProcess(
-        driverExecutable, ['--port', '$port', ...driverArguments])) {
-      return false;
-    }
-    await _createDriver(port);
+    await _createDriver();
     await _driver.get(url);
     try {
       _logEvent('Got version: ${await version}');
@@ -286,14 +283,14 @@
     return true;
   }
 
-  Future<void> _createDriver(int port) async {
+  Future<void> _createDriver() async {
     for (var i = 5; i >= 0; i--) {
       // Give the driver process some time to be ready to accept connections.
       await Future.delayed(const Duration(seconds: 1));
       try {
         _driver = await createDriver(
-            uri: Uri.parse('http://localhost:$port/'),
-            desired: desiredCapabilities);
+            uri: Uri.parse('http://localhost:$_port/'),
+            desired: _desiredCapabilities);
       } catch (error) {
         if (i > 0) {
           _logEvent(
@@ -308,33 +305,10 @@
     }
   }
 
-  /// Returns a port that is probably, but not definitely, not in use.
-  ///
-  /// This has a built-in race condition: another process may bind this port at
-  /// any time after this call has returned.
-  static Future<int> _findUnusedPort() async {
-    int port;
-    ServerSocket socket;
-    try {
-      socket = await ServerSocket.bind(InternetAddress.loopbackIPv6, 0,
-          v6Only: true);
-    } on SocketException {
-      socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
-    }
-    port = socket.port;
-    await socket.close();
-    return port;
-  }
-
   @override
   Future<bool> close() async {
-    try {
-      await _driver?.quit();
-      // Give the driver process some time to be quit the browser.
-      await Future.delayed(const Duration(seconds: 1));
-    } finally {
-      process?.kill();
-    }
+    await _driver?.quit();
+    // Give the driver process some time to be quit the browser.
     return true;
   }
 }
@@ -343,14 +317,11 @@
   /// We get the safari version by parsing a version file
   static const versionFile = '/Applications/Safari.app/Contents/version.plist';
 
-  @override
-  final driverExecutable = '/usr/bin/safaridriver';
-  @override
-  final driverArguments = <String>[];
-  @override
-  final desiredCapabilities = <String, dynamic>{
-    'browserName': 'safari',
-  };
+  Safari(int port)
+      : super(port, {
+          'browserName': 'safari',
+        });
+
   @override
   Future<String> get version async {
     // Example of the file:
diff --git a/pkg/test_runner/lib/src/service/service.dart b/pkg/test_runner/lib/src/service/service.dart
new file mode 100644
index 0000000..25ac0b7
--- /dev/null
+++ b/pkg/test_runner/lib/src/service/service.dart
@@ -0,0 +1,11 @@
+// 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.
+
+enum ServiceState {
+  created,
+  starting,
+  running,
+  failed,
+  stopped,
+}
diff --git a/pkg/test_runner/lib/src/service/web_driver_service.dart b/pkg/test_runner/lib/src/service/web_driver_service.dart
new file mode 100644
index 0000000..9719116
--- /dev/null
+++ b/pkg/test_runner/lib/src/service/web_driver_service.dart
@@ -0,0 +1,73 @@
+// 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.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:smith/smith.dart';
+
+import '../test_progress.dart';
+import 'service.dart';
+
+const safariDriverPort = 7055;
+
+class WebDriverService extends EventListener {
+  static final _instances = <Runtime, WebDriverService>{};
+  static final supportedRuntimes = <Runtime>{
+    Runtime.safari,
+  };
+
+  final String _driverExecutable;
+  final List<String> _driverArguments;
+  Future<void> _started;
+  Process _process;
+
+  ServiceState state = ServiceState.created;
+  final int port;
+
+  WebDriverService(this._driverExecutable, this._driverArguments, this.port);
+
+  Future<void> start() {
+    if (_started != null) {
+      return _started;
+    }
+    return _started = () async {
+      state = ServiceState.starting;
+      try {
+        _process = await Process.start(
+            _driverExecutable, ['--port', '$port', ..._driverArguments]);
+        _process.exitCode.then((exitCode) {
+          if (state != ServiceState.stopped) {
+            state = ServiceState.failed;
+            print('$runtimeType stopped unexpectedly: $exitCode');
+          }
+        });
+        state = ServiceState.running;
+        print('Started $runtimeType on port $port');
+      } catch (error) {
+        state = ServiceState.failed;
+        print('Failed to start $runtimeType: $error');
+        rethrow;
+      }
+    }();
+  }
+
+  @override
+  void allDone() {
+    state = ServiceState.stopped;
+    _process?.kill();
+  }
+
+  factory WebDriverService.fromRuntime(Runtime runtime) {
+    return _instances.putIfAbsent(runtime, () {
+      switch (runtime) {
+        case Runtime.safari:
+          return WebDriverService(
+              '/usr/bin/safaridriver', [], safariDriverPort);
+        default:
+          throw ArgumentError.value(runtime, 'runtime', 'Unsupported runtime');
+      }
+    });
+  }
+}
diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart
index 6d7f1f8..e5157fe 100644
--- a/pkg/test_runner/lib/src/test_configurations.dart
+++ b/pkg/test_runner/lib/src/test_configurations.dart
@@ -13,6 +13,7 @@
 import 'fuchsia.dart';
 import 'path.dart';
 import 'process_queue.dart';
+import 'service/web_driver_service.dart';
 import 'terminal.dart';
 import 'test_progress.dart';
 import 'test_suite.dart';
@@ -89,8 +90,9 @@
   var runningBrowserTests =
       configurations.any((config) => config.runtime.isBrowser);
 
-  var serverFutures = <Future>[];
+  var eventListeners = <EventListener>[];
   var testSuites = <TestSuite>[];
+  var serverFutures = <Future>[];
   var maxBrowserProcesses = maxProcesses;
   if (configurations.length > 1 &&
       (configurations[0].testServerPort != 0 ||
@@ -101,9 +103,13 @@
     exit(1);
   }
 
+  var services = <WebDriverService>{};
   for (var configuration in configurations) {
     if (!listTests && !listStatusFiles && runningBrowserTests) {
       serverFutures.add(configuration.startServers());
+      if (WebDriverService.supportedRuntimes.contains(configuration.runtime)) {
+        services.add(WebDriverService.fromRuntime(configuration.runtime));
+      }
     }
 
     if (configuration.runtime.isIE) {
@@ -170,6 +176,11 @@
     }
   }
 
+  for (var service in services) {
+    serverFutures.add(service.start());
+    eventListeners.add(service);
+  }
+
   // If we only need to print out status files for test suites
   // we return from running here and just print.
   if (firstConf.listStatusFiles) {
@@ -194,8 +205,6 @@
     }
   }
 
-  var eventListener = <EventListener>[];
-
   // We don't print progress if we list tests.
   if (progress != Progress.silent && !listTests) {
     var formatter = Formatter.normal;
@@ -204,53 +213,53 @@
       formatter = Formatter.color;
     }
 
-    eventListener.add(SummaryPrinter());
+    eventListeners.add(SummaryPrinter());
     if (!firstConf.silentFailures) {
-      eventListener.add(TestFailurePrinter(formatter));
+      eventListeners.add(TestFailurePrinter(formatter));
     }
 
     if (firstConf.printPassingStdout) {
-      eventListener.add(PassingStdoutPrinter(formatter));
+      eventListeners.add(PassingStdoutPrinter(formatter));
     }
 
     var indicator =
         ProgressIndicator.fromProgress(progress, startTime, formatter);
-    if (indicator != null) eventListener.add(indicator);
+    if (indicator != null) eventListeners.add(indicator);
 
     if (printTiming) {
-      eventListener.add(TimingPrinter(startTime));
+      eventListeners.add(TimingPrinter(startTime));
     }
 
-    eventListener.add(SkippedCompilationsPrinter());
+    eventListeners.add(SkippedCompilationsPrinter());
 
     if (progress == Progress.status) {
-      eventListener.add(TimedProgressPrinter());
+      eventListeners.add(TimedProgressPrinter());
     }
 
     if (firstConf.reportFailures) {
-      eventListener.add(FailedTestsPrinter());
+      eventListeners.add(FailedTestsPrinter());
     }
 
-    eventListener.add(ResultCountPrinter(formatter));
+    eventListeners.add(ResultCountPrinter(formatter));
   }
 
   if (firstConf.writeResults) {
-    eventListener.add(ResultWriter(firstConf.outputDirectory));
+    eventListeners.add(ResultWriter(firstConf.outputDirectory));
   }
 
   if (firstConf.copyCoreDumps) {
-    eventListener.add(UnexpectedCrashLogger());
+    eventListeners.add(UnexpectedCrashLogger());
   }
 
   // The only progress indicator when listing tests should be the
   // the summary printer.
   if (listTests) {
-    eventListener.add(SummaryPrinter(jsonOnly: reportInJson));
+    eventListeners.add(SummaryPrinter(jsonOnly: reportInJson));
   } else {
     if (!firstConf.cleanExit) {
-      eventListener.add(ExitCodeSetter());
+      eventListeners.add(ExitCodeSetter());
     }
-    eventListener.add(IgnoredTestMonitor());
+    eventListeners.add(IgnoredTestMonitor());
   }
 
   // If any of the configurations need to access android devices we'll first
@@ -270,5 +279,5 @@
 
   // [firstConf] is needed here, because the ProcessQueue uses some settings.
   ProcessQueue(firstConf, maxProcesses, maxBrowserProcesses, testSuites,
-      eventListener, allTestsFinished, verbose, adbDevicePool);
+      eventListeners, allTestsFinished, verbose, adbDevicePool);
 }
diff --git a/pkg/test_runner/test/browser_controller_test.dart b/pkg/test_runner/test/browser_controller_test.dart
index c801de2..b9738e0 100644
--- a/pkg/test_runner/test/browser_controller_test.dart
+++ b/pkg/test_runner/test/browser_controller_test.dart
@@ -5,8 +5,9 @@
 import 'dart:io';
 
 import 'package:expect/expect.dart';
-
+import 'package:smith/smith.dart';
 import 'package:test_runner/src/browser_controller.dart';
+import 'package:test_runner/src/service/web_driver_service.dart';
 
 void main() async {
   if (Platform.environment.containsKey('CHROME_PATH')) {
@@ -31,8 +32,11 @@
   return testBrowser(Firefox(Platform.environment['FIREFOX_PATH']));
 }
 
-Future<void> testSafari() {
-  return testBrowser(Safari());
+Future<void> testSafari() async {
+  var service = WebDriverService.fromRuntime(Runtime.safari);
+  await service.start();
+  await testBrowser(Safari(service.port));
+  service.allDone();
 }
 
 Future<void> testBrowser(Browser browser) async {
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index c8f2ca5..178aedf 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -1030,9 +1030,9 @@
         s->WriteTokenPosition(func->untag()->token_pos_);
         s->WriteTokenPosition(func->untag()->end_token_pos_);
         s->Write<uint32_t>(func->untag()->kernel_offset_);
+        s->Write<uint32_t>(func->untag()->packed_fields_);
       }
 
-      s->Write<uint32_t>(func->untag()->packed_fields_);
       s->Write<uint32_t>(func->untag()->kind_tag_);
     }
   }
@@ -1192,8 +1192,8 @@
       func->untag()->end_token_pos_ = d.ReadTokenPosition();
       func->untag()->kernel_offset_ = d.Read<uint32_t>();
       func->untag()->unboxed_parameters_info_.Reset();
-#endif
       func->untag()->packed_fields_ = d.Read<uint32_t>();
+#endif
       func->untag()->kind_tag_ = d.Read<uint32_t>();
 #if !defined(DART_PRECOMPILED_RUNTIME)
       func->untag()->usage_counter_ = 0;
diff --git a/runtime/vm/canonical_tables.cc b/runtime/vm/canonical_tables.cc
index bfdc140..d2fd487 100644
--- a/runtime/vm/canonical_tables.cc
+++ b/runtime/vm/canonical_tables.cc
@@ -69,4 +69,46 @@
   UNREACHABLE();
 }
 
+CanonicalInstanceKey::CanonicalInstanceKey(const Instance& key) : key_(key) {
+  ASSERT(!(key.IsString() || key.IsAbstractType()));
+}
+
+bool CanonicalInstanceKey::Matches(const Instance& obj) const {
+  ASSERT(!(obj.IsString() || obj.IsAbstractType()));
+  if (key_.CanonicalizeEquals(obj)) {
+    ASSERT(obj.IsCanonical());
+    return true;
+  }
+  return false;
+}
+
+uword CanonicalInstanceKey::Hash() const {
+  return key_.CanonicalizeHash();
+}
+
+bool CanonicalInstanceTraits::IsMatch(const Object& a, const Object& b) {
+  ASSERT(!(a.IsString() || a.IsAbstractType()));
+  ASSERT(!(b.IsString() || b.IsAbstractType()));
+  return a.ptr() == b.ptr();
+}
+
+bool CanonicalInstanceTraits::IsMatch(const CanonicalInstanceKey& a,
+                                      const Object& b) {
+  return a.Matches(Instance::Cast(b));
+}
+
+uword CanonicalInstanceTraits::Hash(const Object& key) {
+  ASSERT(!(key.IsString() || key.IsAbstractType()));
+  ASSERT(key.IsInstance());
+  return Instance::Cast(key).CanonicalizeHash();
+}
+
+uword CanonicalInstanceTraits::Hash(const CanonicalInstanceKey& key) {
+  return key.Hash();
+}
+
+ObjectPtr CanonicalInstanceTraits::NewKey(const CanonicalInstanceKey& obj) {
+  return obj.key_.ptr();
+}
+
 }  // namespace dart
diff --git a/runtime/vm/canonical_tables.h b/runtime/vm/canonical_tables.h
index ba9297e..f4f758f 100644
--- a/runtime/vm/canonical_tables.h
+++ b/runtime/vm/canonical_tables.h
@@ -303,6 +303,31 @@
 };
 typedef UnorderedHashMap<MetadataMapTraits> MetadataMap;
 
+class CanonicalInstanceKey {
+ public:
+  explicit CanonicalInstanceKey(const Instance& key);
+  bool Matches(const Instance& obj) const;
+  uword Hash() const;
+  const Instance& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical Instances based on a hash of the fields.
+class CanonicalInstanceTraits {
+ public:
+  static const char* Name() { return "CanonicalInstanceTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b);
+  static bool IsMatch(const CanonicalInstanceKey& a, const Object& b);
+  static uword Hash(const Object& key);
+  static uword Hash(const CanonicalInstanceKey& key);
+  static ObjectPtr NewKey(const CanonicalInstanceKey& obj);
+};
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_CANONICAL_TABLES_H_
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index b58ff26..4e9be6f 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -4,6 +4,8 @@
 
 #include "vm/compiler/aot/precompiler.h"
 
+#include <memory>
+
 #include "platform/unicode.h"
 #include "platform/utils.h"
 #include "vm/canonical_tables.h"
@@ -400,6 +402,7 @@
       dropped_functiontype_count_(0),
       dropped_typeparam_count_(0),
       dropped_library_count_(0),
+      dropped_constants_arrays_entries_count_(0),
       libraries_(GrowableObjectArray::Handle(
           isolate_->group()->object_store()->libraries())),
       pending_functions_(
@@ -607,6 +610,7 @@
 
         DropFunctions();
         DropFields();
+        DropTransitiveUserDefinedConstants();
         TraceTypesFromRetainedClasses();
 
         // Clear these before dropping classes as they may hold onto otherwise
@@ -688,7 +692,9 @@
     THR_Print(" %" Pd " type parameters,", dropped_typeparam_count_);
     THR_Print(" %" Pd " type arguments,", dropped_typearg_count_);
     THR_Print(" %" Pd " classes,", dropped_class_count_);
-    THR_Print(" %" Pd " libraries.\n", dropped_library_count_);
+    THR_Print(" %" Pd " libraries,", dropped_library_count_);
+    THR_Print(" %" Pd " constants arrays entries.\n",
+              dropped_constants_arrays_entries_count_);
   }
 }
 
@@ -2420,6 +2426,190 @@
          StubCode::TopTypeTypeTest().EntryPoint());
 }
 
+enum ConstantVisitedValue { kNotVisited = 0, kRetain, kDrop };
+
+static bool IsUserDefinedClass(Zone* zone,
+                               ClassPtr cls,
+                               ObjectStore* object_store) {
+  intptr_t cid = cls.untag()->id();
+  if (cid < kNumPredefinedCids) {
+    return false;
+  }
+
+  const UntaggedClass* untagged_cls = cls.untag();
+  return ((untagged_cls->library() != object_store->core_library()) &&
+          (untagged_cls->library() != object_store->collection_library()) &&
+          (untagged_cls->library() != object_store->typed_data_library()));
+}
+
+/// Updates |visited| weak table with information about whether object
+/// (transitevly) references constants of user-defined classes: |kDrop|
+/// indicates it does, |kRetain| - does not.
+class ConstantInstanceVisitor {
+ public:
+  ConstantInstanceVisitor(Zone* zone,
+                          WeakTable* visited,
+                          ObjectStore* object_store)
+      : zone_(zone),
+        visited_(visited),
+        object_store_(object_store),
+        object_(Object::Handle(zone)),
+        array_(Array::Handle(zone)) {}
+
+  void Visit(ObjectPtr object_ptr) {
+    if (!object_ptr->IsHeapObject()) {
+      return;
+    }
+    ConstantVisitedValue value = static_cast<ConstantVisitedValue>(
+        visited_->GetValueExclusive(object_ptr));
+    if (value != kNotVisited) {
+      return;
+    }
+    object_ = object_ptr;
+    if (IsUserDefinedClass(zone_, object_.clazz(), object_store_)) {
+      visited_->SetValueExclusive(object_ptr, kDrop);
+      return;
+    }
+
+    // Conservatively assume an object will be retained.
+    visited_->SetValueExclusive(object_ptr, kRetain);
+    switch (object_ptr.untag()->GetClassId()) {
+      case kImmutableArrayCid: {
+        array_ ^= object_ptr;
+        for (intptr_t i = 0; i < array_.Length(); i++) {
+          ObjectPtr element = array_.At(i);
+          Visit(element);
+          if (static_cast<ConstantVisitedValue>(
+                  visited_->GetValueExclusive(element)) == kDrop) {
+            visited_->SetValueExclusive(object_ptr, kDrop);
+            break;
+          }
+        }
+        break;
+      }
+      case kImmutableLinkedHashMapCid: {
+        const LinkedHashMap& map =
+            LinkedHashMap::Handle(LinkedHashMap::RawCast(object_ptr));
+        LinkedHashMap::Iterator iterator(map);
+        while (iterator.MoveNext()) {
+          ObjectPtr element = iterator.CurrentKey();
+          Visit(element);
+          if (static_cast<ConstantVisitedValue>(
+                  visited_->GetValueExclusive(element)) == kDrop) {
+            visited_->SetValueExclusive(object_ptr, kDrop);
+            break;
+          }
+          element = iterator.CurrentValue();
+          Visit(element);
+          if (static_cast<ConstantVisitedValue>(
+                  visited_->GetValueExclusive(element)) == kDrop) {
+            visited_->SetValueExclusive(object_ptr, kDrop);
+            break;
+          }
+        }
+        break;
+      }
+      case kImmutableLinkedHashSetCid: {
+        const LinkedHashSet& set =
+            LinkedHashSet::Handle(LinkedHashSet::RawCast(object_ptr));
+        LinkedHashSet::Iterator iterator(set);
+        while (iterator.MoveNext()) {
+          ObjectPtr element = iterator.CurrentKey();
+          Visit(element);
+          if (static_cast<ConstantVisitedValue>(
+                  visited_->GetValueExclusive(element)) == kDrop) {
+            visited_->SetValueExclusive(object_ptr, kDrop);
+            break;
+          }
+        }
+        break;
+      }
+    }
+  }
+
+ private:
+  Zone* zone_;
+  WeakTable* visited_;
+  ObjectStore* object_store_;
+  Object& object_;
+  Array& array_;
+};
+
+// To reduce snapshot size, we remove from constant tables all constants that
+// cannot be sent in messages between isolate groups. Such constants will not
+// be canonicalized at runtime.
+void Precompiler::DropTransitiveUserDefinedConstants() {
+  HANDLESCOPE(T);
+  auto& constants = Array::Handle(Z);
+  auto& obj = Object::Handle(Z);
+  auto& lib = Library::Handle(Z);
+  auto& cls = Class::Handle(Z);
+  auto& instance = Instance::Handle(Z);
+
+  {
+    NoSafepointScope no_safepoint(T);
+    std::unique_ptr<WeakTable> visited(new WeakTable());
+    ObjectStore* object_store = IG->object_store();
+    ConstantInstanceVisitor visitor(Z, visited.get(), object_store);
+
+    for (intptr_t i = 0; i < libraries_.Length(); i++) {
+      lib ^= libraries_.At(i);
+      HANDLESCOPE(T);
+      ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+      while (it.HasNext()) {
+        cls = it.GetNextClass();
+        if (cls.constants() == Array::null()) {
+          continue;
+        }
+        typedef UnorderedHashSet<CanonicalInstanceTraits> CanonicalInstancesSet;
+
+        CanonicalInstancesSet constants_set(cls.constants());
+        CanonicalInstancesSet::Iterator iterator(&constants_set);
+
+        if (IsUserDefinedClass(Z, cls.ptr(), object_store)) {
+          // All constants for user-defined classes can be dropped.
+          constants = cls.constants();
+          dropped_constants_arrays_entries_count_ += constants.Length();
+          if (FLAG_trace_precompiler) {
+            THR_Print("Dropping %" Pd " entries from constants for class %s\n",
+                      constants.Length(), cls.ToCString());
+          }
+          while (iterator.MoveNext()) {
+            obj = constants_set.GetKey(iterator.Current());
+            instance = Instance::RawCast(obj.ptr());
+            consts_to_retain_.Remove(&instance);
+            visited->SetValueExclusive(obj.ptr(), kDrop);
+          }
+        } else {
+          // Core classes might have constants that refer to user-defined
+          // classes. Those should be dropped too.
+          while (iterator.MoveNext()) {
+            obj = constants_set.GetKey(iterator.Current());
+            ConstantVisitedValue value = static_cast<ConstantVisitedValue>(
+                visited->GetValueExclusive(obj.ptr()));
+            if (value == kNotVisited) {
+              visitor.Visit(obj.ptr());
+              value = static_cast<ConstantVisitedValue>(
+                  visited->GetValueExclusive(obj.ptr()));
+            }
+            ASSERT(value == kDrop || value == kRetain);
+            if (value == kDrop) {
+              dropped_constants_arrays_entries_count_++;
+              if (FLAG_trace_precompiler) {
+                THR_Print("Dropping constant entry for class %s instance:%s\n",
+                          cls.ToCString(), obj.ToCString());
+              }
+              instance = Instance::RawCast(obj.ptr());
+              consts_to_retain_.Remove(&instance);
+            }
+          }
+        }
+        constants_set.Release();
+      }
+    }
+  }
+}
+
 void Precompiler::TraceTypesFromRetainedClasses() {
   HANDLESCOPE(T);
   auto& lib = Library::Handle(Z);
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index ba2aee7..4e0d211 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -333,6 +333,10 @@
   void ReplaceFunctionStaticCallEntries();
   void DropFunctions();
   void DropFields();
+  void VisitConstantInstance(ObjectPtr instance,
+                             WeakTable* visited,
+                             ObjectStore* object_store);
+  void DropTransitiveUserDefinedConstants();
   void TraceTypesFromRetainedClasses();
   void DropMetadata();
   void DropLibraryEntries();
@@ -370,6 +374,7 @@
   intptr_t dropped_functiontype_count_;
   intptr_t dropped_typeparam_count_;
   intptr_t dropped_library_count_;
+  intptr_t dropped_constants_arrays_entries_count_;
 
   compiler::ObjectPoolBuilder global_object_pool_builder_;
   GrowableObjectArray& libraries_;
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 771887e..dac6e38 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -2455,6 +2455,16 @@
   ldm(IA_W, SP, regs, cond);
 }
 
+void Assembler::PushQuad(FpuRegister reg, Condition cond) {
+  DRegister dreg = EvenDRegisterOf(reg);
+  vstmd(DB_W, SP, dreg, 2, cond);  // 2 D registers per Q register.
+}
+
+void Assembler::PopQuad(FpuRegister reg, Condition cond) {
+  DRegister dreg = EvenDRegisterOf(reg);
+  vldmd(IA_W, SP, dreg, 2, cond);  // 2 D registers per Q register.
+}
+
 void Assembler::PushRegisters(const RegisterSet& regs) {
   const intptr_t fpu_regs_count = regs.FpuRegisterCount();
   if (fpu_regs_count > 0) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 821426e..ff2af91 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -1134,6 +1134,9 @@
   void PushList(RegList regs, Condition cond = AL);
   void PopList(RegList regs, Condition cond = AL);
 
+  void PushQuad(FpuRegister rd, Condition cond = AL);
+  void PopQuad(FpuRegister rd, Condition cond = AL);
+
   void PushRegisters(const RegisterSet& regs);
   void PopRegisters(const RegisterSet& regs);
 
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 8d90c0f..ade3a3e 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -854,91 +854,62 @@
   }
 }
 
+Address Assembler::PrepareLargeOffset(Register base,
+                                      int32_t offset,
+                                      OperandSize sz) {
+  if (Address::CanHoldOffset(offset, Address::Offset, sz)) {
+    return Address(base, offset, Address::Offset, sz);
+  }
+  ASSERT(base != TMP2);
+  Operand op;
+  const uint32_t upper20 = offset & 0xfffff000;
+  const uint32_t lower12 = offset & 0x00000fff;
+  if ((base != CSP) &&
+      (Operand::CanHold(upper20, kXRegSizeInBits, &op) == Operand::Immediate) &&
+      Address::CanHoldOffset(lower12, Address::Offset, sz)) {
+    add(TMP2, base, op);
+    return Address(TMP2, lower12, Address::Offset, sz);
+  }
+  LoadImmediate(TMP2, offset);
+  return Address(base, TMP2);
+}
+
 void Assembler::LoadFromOffset(Register dest,
                                Register base,
                                int32_t offset,
                                OperandSize sz) {
-  if (Address::CanHoldOffset(offset, Address::Offset, sz)) {
-    LoadFromOffset(dest, Address(base, offset, Address::Offset, sz), sz);
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    LoadFromOffset(dest, Address(TMP2), sz);
-  }
+  LoadFromOffset(dest, PrepareLargeOffset(base, offset, sz), sz);
 }
 
 void Assembler::LoadSFromOffset(VRegister dest, Register base, int32_t offset) {
-  if (Address::CanHoldOffset(offset, Address::Offset, kSWord)) {
-    fldrs(dest, Address(base, offset, Address::Offset, kSWord));
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    fldrs(dest, Address(TMP2));
-  }
+  fldrs(dest, PrepareLargeOffset(base, offset, kSWord));
 }
 
 void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) {
-  if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) {
-    fldrd(dest, Address(base, offset, Address::Offset, kDWord));
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    fldrd(dest, Address(TMP2));
-  }
+  fldrd(dest, PrepareLargeOffset(base, offset, kDWord));
 }
 
 void Assembler::LoadQFromOffset(VRegister dest, Register base, int32_t offset) {
-  if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) {
-    fldrq(dest, Address(base, offset, Address::Offset, kQWord));
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    fldrq(dest, Address(TMP2));
-  }
+  fldrq(dest, PrepareLargeOffset(base, offset, kQWord));
 }
 
 void Assembler::StoreToOffset(Register src,
                               Register base,
                               int32_t offset,
                               OperandSize sz) {
-  ASSERT(base != TMP2);
-  if (Address::CanHoldOffset(offset, Address::Offset, sz)) {
-    StoreToOffset(src, Address(base, offset, Address::Offset, sz), sz);
-  } else {
-    ASSERT(src != TMP2);
-    AddImmediate(TMP2, base, offset);
-    StoreToOffset(src, Address(TMP2), sz);
-  }
+  StoreToOffset(src, PrepareLargeOffset(base, offset, sz), sz);
 }
 
 void Assembler::StoreSToOffset(VRegister src, Register base, int32_t offset) {
-  if (Address::CanHoldOffset(offset, Address::Offset, kSWord)) {
-    fstrs(src, Address(base, offset, Address::Offset, kSWord));
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    fstrs(src, Address(TMP2));
-  }
+  fstrs(src, PrepareLargeOffset(base, offset, kSWord));
 }
 
 void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) {
-  if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) {
-    fstrd(src, Address(base, offset, Address::Offset, kDWord));
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    fstrd(src, Address(TMP2));
-  }
+  fstrd(src, PrepareLargeOffset(base, offset, kDWord));
 }
 
 void Assembler::StoreQToOffset(VRegister src, Register base, int32_t offset) {
-  if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) {
-    fstrq(src, Address(base, offset, Address::Offset, kQWord));
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    fstrq(src, Address(TMP2));
-  }
+  fstrq(src, PrepareLargeOffset(base, offset, kQWord));
 }
 
 void Assembler::VRecps(VRegister vd, VRegister vn) {
@@ -984,17 +955,9 @@
                                          Register base,
                                          int32_t offset) {
 #if !defined(DART_COMPRESSED_POINTERS)
-  LoadFromOffset(dest, base, offset);
+  LoadFromOffset(dest, base, offset, kObjectBytes);
 #else
-  if (Address::CanHoldOffset(offset, Address::Offset, kObjectBytes)) {
-    ldr(dest, Address(base, offset, Address::Offset, kObjectBytes),
-        kUnsignedFourBytes);  // Zero-extension.
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    ldr(dest, Address(TMP2, 0, Address::Offset, kObjectBytes),
-        kUnsignedFourBytes);  // Zero-extension.
-  }
+  LoadFromOffset(dest, base, offset, kUnsignedFourBytes);  // Zero-extension.
   add(dest, dest, Operand(HEAP_BITS, LSL, 32));
 #endif
 }
@@ -1019,15 +982,7 @@
 #if !defined(DART_COMPRESSED_POINTERS)
   LoadFromOffset(dest, base, offset);
 #else
-  if (Address::CanHoldOffset(offset, Address::Offset, kObjectBytes)) {
-    ldr(dest, Address(base, offset, Address::Offset, kObjectBytes),
-        kUnsignedFourBytes);  // Zero-extension.
-  } else {
-    ASSERT(base != TMP2);
-    AddImmediate(TMP2, base, offset);
-    ldr(dest, Address(TMP2, 0, Address::Offset, kObjectBytes),
-        kUnsignedFourBytes);  // Zero-extension.
-  }
+  LoadFromOffset(dest, base, offset, kUnsignedFourBytes);  // Zero-extension.
 #endif
 #if defined(DEBUG)
   Label done;
@@ -1081,11 +1036,8 @@
                                       MemoryOrder memory_order) {
   if (memory_order == kRelease) {
     StoreRelease(value, object, offset);
-  } else if (FieldAddress::CanHoldOffset(offset)) {
-    str(value, FieldAddress(object, offset));
   } else {
-    AddImmediate(TMP, object, offset - kHeapObjectTag);
-    str(value, Address(TMP));
+    StoreToOffset(value, object, offset - kHeapObjectTag);
   }
   StoreBarrier(object, value, value_can_be_smi);
 }
@@ -1097,11 +1049,8 @@
                                                 MemoryOrder memory_order) {
   if (memory_order == kRelease) {
     StoreReleaseCompressed(value, object, offset);
-  } else if (FieldAddress::CanHoldOffset(offset)) {
-    str(value, FieldAddress(object, offset), kObjectBytes);
   } else {
-    AddImmediate(TMP, object, offset - kHeapObjectTag);
-    str(value, Address(TMP), kObjectBytes);
+    StoreToOffset(value, object, offset - kHeapObjectTag, kObjectBytes);
   }
   StoreBarrier(object, value, value_can_be_smi);
 }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 116083a..0429fc0 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1840,6 +1840,7 @@
   void TestImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes);
   void CompareImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes);
 
+  Address PrepareLargeOffset(Register base, int32_t offset, OperandSize sz);
   void LoadFromOffset(Register dest,
                       const Address& address,
                       OperandSize sz = kEightBytes) override {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 6bdd476..e737994 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -1271,15 +1271,11 @@
 }
 
 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
-  DRegister dreg = EvenDRegisterOf(reg);
-  __ vstrd(dreg,
-           compiler::Address(SP, -kDoubleSize, compiler::Address::PreIndex));
+  __ PushQuad(reg);
 }
 
 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
-  DRegister dreg = EvenDRegisterOf(reg);
-  __ vldrd(dreg,
-           compiler::Address(SP, kDoubleSize, compiler::Address::PostIndex));
+  __ PopQuad(reg);
 }
 
 #undef __
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index b4f95bd..d7a6ff6 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -1234,11 +1234,11 @@
 }
 
 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
-  __ PushDouble(reg);
+  __ PushQuad(reg);
 }
 
 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
-  __ PopDouble(reg);
+  __ PopQuad(reg);
 }
 
 #undef __
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc b/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
index c129e1b..6e0172d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
@@ -819,7 +819,7 @@
     } else if (destination.IsFpuRegister()) {
       const intptr_t src_offset = source.ToStackSlotOffset();
       FRegister dst = destination.fpu_reg();
-      __ fld(dst, compiler::Address(source.base_reg(), src_offset));
+      __ LoadDFromOffset(dst, source.base_reg(), src_offset);
     } else {
       ASSERT(destination.IsStackSlot());
       const intptr_t source_offset = source.ToStackSlotOffset();
@@ -837,7 +837,7 @@
           destination.IsDoubleStackSlot()) {
         const intptr_t dest_offset = destination.ToStackSlotOffset();
         FRegister src = source.fpu_reg();
-        __ fsd(src, compiler::Address(destination.base_reg(), dest_offset));
+        __ StoreDToOffset(src, destination.base_reg(), dest_offset);
       } else {
         ASSERT(destination.IsQuadStackSlot());
         UNIMPLEMENTED();
@@ -847,14 +847,14 @@
     if (destination.IsFpuRegister()) {
       const intptr_t source_offset = source.ToStackSlotOffset();
       const FRegister dst = destination.fpu_reg();
-      __ fld(dst, compiler::Address(source.base_reg(), source_offset));
+      __ LoadDFromOffset(dst, source.base_reg(), source_offset);
     } else {
       ASSERT(destination.IsDoubleStackSlot() ||
              destination.IsStackSlot() /*32-bit float*/);
       const intptr_t source_offset = source.ToStackSlotOffset();
       const intptr_t dest_offset = destination.ToStackSlotOffset();
-      __ fld(FTMP, compiler::Address(source.base_reg(), source_offset));
-      __ fsd(FTMP, compiler::Address(destination.base_reg(), dest_offset));
+      __ LoadDFromOffset(FTMP, source.base_reg(), source_offset);
+      __ StoreDToOffset(FTMP, destination.base_reg(), dest_offset);
     }
   } else if (source.IsQuadStackSlot()) {
     UNIMPLEMENTED();
diff --git a/runtime/vm/compiler/backend/flow_graph_test.cc b/runtime/vm/compiler/backend/flow_graph_test.cc
index 8f82bb1..d97244f 100644
--- a/runtime/vm/compiler/backend/flow_graph_test.cc
+++ b/runtime/vm/compiler/backend/flow_graph_test.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "platform/text_buffer.h"
 #include "platform/utils.h"
 #include "vm/compiler/backend/block_builder.h"
 #include "vm/compiler/backend/il_printer.h"
@@ -146,4 +147,101 @@
   EXPECT_PROPERTY(late_var, it.representation() == kTagged);
 }
 
+void TestLargeFrame(const char* type,
+                    const char* zero,
+                    const char* one,
+                    const char* main) {
+  SetFlagScope<int> sfs(&FLAG_optimization_counter_threshold, 1000);
+  TextBuffer printer(256 * KB);
+
+  intptr_t num_locals = 2000;
+  printer.Printf("import 'dart:typed_data';\n");
+  printer.Printf("@pragma('vm:never-inline')\n");
+  printer.Printf("%s one() { return %s; }\n", type, one);
+  printer.Printf("@pragma('vm:never-inline')\n");
+  printer.Printf("%s largeFrame(int n) {\n", type);
+  for (intptr_t i = 0; i < num_locals; i++) {
+    printer.Printf("  %s local%" Pd " = %s;\n", type, i, zero);
+  }
+  printer.Printf("  for (int i = 0; i < n; i++) {\n");
+  for (intptr_t i = 0; i < num_locals; i++) {
+    printer.Printf("    local%" Pd " += one();\n", i);
+  }
+  printer.Printf("  }\n");
+  printer.Printf("  %s sum = %s;\n", type, zero);
+  for (intptr_t i = 0; i < num_locals; i++) {
+    printer.Printf("    sum += local%" Pd ";\n", i);
+  }
+  printer.Printf("  return sum;\n");
+  printer.Printf("}\n");
+
+  printer.AddString(main);
+
+  const auto& root_library = Library::Handle(LoadTestScript(printer.buffer()));
+  Invoke(root_library, "main");
+}
+
+ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Int) {
+  TestLargeFrame("int", "0", "1",
+                 "main() {\n"
+                 "  for (var i = 0; i < 100; i++) {\n"
+                 "    var r = largeFrame(1);\n"
+                 "    if (r != 2000) throw r;\n"
+                 "  }\n"
+                 "  return 'Okay';\n"
+                 "}\n");
+}
+
+ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Double) {
+  TestLargeFrame("double", "0.0", "1.0",
+                 "main() {\n"
+                 "  for (var i = 0; i < 100; i++) {\n"
+                 "    var r = largeFrame(1);\n"
+                 "    if (r != 2000.0) throw r;\n"
+                 "  }\n"
+                 "  return 'Okay';\n"
+                 "}\n");
+}
+
+ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Int32x4) {
+  TestLargeFrame("Int32x4", "Int32x4(0, 0, 0, 0)", "Int32x4(1, 2, 3, 4)",
+                 "main() {\n"
+                 "  for (var i = 0; i < 100; i++) {\n"
+                 "    var r = largeFrame(1);\n"
+                 "    if (r.x != 2000) throw r;\n"
+                 "    if (r.y != 4000) throw r;\n"
+                 "    if (r.z != 6000) throw r;\n"
+                 "    if (r.w != 8000) throw r;\n"
+                 "  }\n"
+                 "  return 'Okay';\n"
+                 "}\n");
+}
+
+ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Float32x4) {
+  TestLargeFrame("Float32x4", "Float32x4(0.0, 0.0, 0.0, 0.0)",
+                 "Float32x4(1.0, 2.0, 3.0, 4.0)",
+                 "main() {\n"
+                 "  for (var i = 0; i < 100; i++) {\n"
+                 "    var r = largeFrame(1);\n"
+                 "    if (r.x != 2000.0) throw r;\n"
+                 "    if (r.y != 4000.0) throw r;\n"
+                 "    if (r.z != 6000.0) throw r;\n"
+                 "    if (r.w != 8000.0) throw r;\n"
+                 "  }\n"
+                 "  return 'Okay';\n"
+                 "}\n");
+}
+
+ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Float64x2) {
+  TestLargeFrame("Float64x2", "Float64x2(0.0, 0.0)", "Float64x2(1.0, 2.0)",
+                 "main() {\n"
+                 "  for (var i = 0; i < 100; i++) {\n"
+                 "    var r = largeFrame(1);\n"
+                 "    if (r.x != 2000.0) throw r;\n"
+                 "    if (r.y != 4000.0) throw r;\n"
+                 "  }\n"
+                 "  return 'Okay';\n"
+                 "}\n");
+}
+
 }  // namespace dart
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index e4efe29..eb87355 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -177,7 +177,6 @@
   V(FinalizerEntry, UntaggedFinalizerEntry, external_size, IntPtr, VAR)        \
   V(Function, UntaggedFunction, entry_point, Uword, FINAL)                     \
   V(Function, UntaggedFunction, kind_tag, Uint32, FINAL)                       \
-  V(Function, UntaggedFunction, packed_fields, Uint32, FINAL)                  \
   V(FunctionType, UntaggedFunctionType, packed_parameter_counts, Uint32,       \
     FINAL)                                                                     \
   V(FunctionType, UntaggedFunctionType, packed_type_parameter_counts, Uint16,  \
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 31c7822..22befb9 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -508,7 +508,6 @@
   static word data_offset();
   static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal);
   static word kind_tag_offset();
-  static word packed_fields_offset();
   static word signature_offset();
   static word usage_counter_offset();
   static word InstanceSize();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 2fc188c..1a4718e 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -161,8 +161,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    83;
 static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
@@ -782,8 +780,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    123;
 static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -1408,8 +1404,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    83;
 static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
@@ -2026,8 +2020,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    123;
 static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -2653,8 +2645,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    91;
 static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -3279,8 +3269,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    91;
 static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -3906,8 +3894,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    83;
 static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
@@ -4529,8 +4515,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    123;
 static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -5153,8 +5137,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    83;
 static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
@@ -5768,8 +5750,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    123;
 static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -6388,8 +6368,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    83;
 static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
@@ -7000,8 +6978,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    123;
 static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -7621,8 +7597,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    91;
 static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -8241,8 +8215,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    91;
 static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -8862,8 +8834,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    83;
 static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
@@ -9479,8 +9449,6 @@
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
-static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    123;
 static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
@@ -10119,8 +10087,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 40;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     20;
 static constexpr dart::compiler::target::word
@@ -10581,7 +10547,7 @@
     24;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
@@ -10816,8 +10782,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     40;
 static constexpr dart::compiler::target::word
@@ -11519,8 +11483,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     40;
 static constexpr dart::compiler::target::word
@@ -12219,8 +12181,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     32;
 static constexpr dart::compiler::target::word
@@ -12918,8 +12878,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     32;
 static constexpr dart::compiler::target::word
@@ -13618,8 +13576,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 40;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     20;
 static constexpr dart::compiler::target::word
@@ -14082,7 +14038,7 @@
     24;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
@@ -14317,8 +14273,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     40;
 static constexpr dart::compiler::target::word
@@ -15014,8 +14968,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 40;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     20;
 static constexpr dart::compiler::target::word
@@ -15474,7 +15426,7 @@
     24;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
@@ -15704,8 +15656,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     40;
 static constexpr dart::compiler::target::word
@@ -16400,8 +16350,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     40;
 static constexpr dart::compiler::target::word
@@ -17093,8 +17041,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     32;
 static constexpr dart::compiler::target::word
@@ -17785,8 +17731,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     32;
 static constexpr dart::compiler::target::word
@@ -18478,8 +18422,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 40;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     20;
 static constexpr dart::compiler::target::word
@@ -18940,7 +18882,7 @@
     24;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
@@ -19170,8 +19112,6 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
-static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
     40;
 static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 04aa47b..2e7c90f 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -133,7 +133,6 @@
   RANGE(Function, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal,   \
         CodeEntryKind::kUnchecked, [](CodeEntryKind value) { return true; })   \
   FIELD(Function, kind_tag_offset)                                             \
-  FIELD(Function, packed_fields_offset)                                        \
   FIELD(Function, signature_offset)                                            \
   FIELD(FutureOr, type_arguments_offset)                                       \
   FIELD(GrowableObjectArray, data_offset)                                      \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index c38de03..4f03fb7a 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2844,13 +2844,15 @@
 DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* len) {
   Thread* thread = Thread::Current();
   DARTSCOPE(thread);
-  ReusableObjectHandleScope reused_obj_handle(thread);
-  const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str);
-  if (str_obj.IsNull()) {
-    RETURN_TYPE_ERROR(thread->zone(), str, String);
+  {
+    ReusableObjectHandleScope reused_obj_handle(thread);
+    const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str);
+    if (!str_obj.IsNull()) {
+      *len = str_obj.Length();
+      return Api::Success();
+    }
   }
-  *len = str_obj.Length();
-  return Api::Success();
+  RETURN_TYPE_ERROR(thread->zone(), str, String);
 }
 
 DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str) {
@@ -3044,16 +3046,18 @@
   Thread* thread = Thread::Current();
   CHECK_ISOLATE(thread->isolate());
   TransitionNativeToVM transition(thread);
-  ReusableObjectHandleScope reused_obj_handle(thread);
-  const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str);
-  if (str_obj.IsNull()) {
-    RETURN_TYPE_ERROR(thread->zone(), str, String);
-  }
   if (size == NULL) {
     RETURN_NULL_ERROR(size);
   }
-  *size = (str_obj.Length() * str_obj.CharSize());
-  return Api::Success();
+  {
+    ReusableObjectHandleScope reused_obj_handle(thread);
+    const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str);
+    if (!str_obj.IsNull()) {
+      *size = (str_obj.Length() * str_obj.CharSize());
+      return Api::Success();
+    }
+  }
+  RETURN_TYPE_ERROR(thread->zone(), str, String);
 }
 
 DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle object,
@@ -3063,21 +3067,23 @@
   Thread* thread = Thread::Current();
   CHECK_ISOLATE(thread->isolate());
   TransitionNativeToVM transition(thread);
-  ReusableObjectHandleScope reused_obj_handle(thread);
-  const String& str = Api::UnwrapStringHandle(reused_obj_handle, object);
-  if (str.IsNull()) {
-    RETURN_TYPE_ERROR(thread->zone(), object, String);
+  {
+    ReusableObjectHandleScope reused_obj_handle(thread);
+    const String& str = Api::UnwrapStringHandle(reused_obj_handle, object);
+    if (!str.IsNull()) {
+      if (str.IsExternal()) {
+        *peer = str.GetPeer();
+        ASSERT(*peer != NULL);
+      } else {
+        NoSafepointScope no_safepoint_scope;
+        *peer = thread->heap()->GetPeer(str.ptr());
+      }
+      *char_size = str.CharSize();
+      *str_len = str.Length();
+      return Api::Success();
+    }
   }
-  if (str.IsExternal()) {
-    *peer = str.GetPeer();
-    ASSERT(*peer != NULL);
-  } else {
-    NoSafepointScope no_safepoint_scope;
-    *peer = thread->heap()->GetPeer(str.ptr());
-  }
-  *char_size = str.CharSize();
-  *str_len = str.Length();
-  return Api::Success();
+  RETURN_TYPE_ERROR(thread->zone(), object, String);
 }
 
 // --- Lists ---
@@ -4927,13 +4933,16 @@
   Thread* thread = Thread::Current();
   CHECK_ISOLATE(thread->isolate());
   TransitionNativeToVM transition(thread);
-  ReusableObjectHandleScope reused_obj_handle(thread);
-  const Instance& instance = Api::UnwrapInstanceHandle(reused_obj_handle, obj);
-  if (instance.IsNull()) {
-    RETURN_TYPE_ERROR(thread->zone(), obj, Instance);
+  {
+    ReusableObjectHandleScope reused_obj_handle(thread);
+    const Instance& instance =
+        Api::UnwrapInstanceHandle(reused_obj_handle, obj);
+    if (!instance.IsNull()) {
+      *count = instance.NumNativeFields();
+      return Api::Success();
+    }
   }
-  *count = instance.NumNativeFields();
-  return Api::Success();
+  RETURN_TYPE_ERROR(thread->zone(), obj, Instance);
 }
 
 DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj,
@@ -4942,18 +4951,26 @@
   Thread* thread = Thread::Current();
   CHECK_ISOLATE(thread->isolate());
   TransitionNativeToVM transition(thread);
-  ReusableObjectHandleScope reused_obj_handle(thread);
-  const Instance& instance = Api::UnwrapInstanceHandle(reused_obj_handle, obj);
-  if (instance.IsNull()) {
+  bool is_null = false;
+  {
+    ReusableObjectHandleScope reused_obj_handle(thread);
+    const Instance& instance =
+        Api::UnwrapInstanceHandle(reused_obj_handle, obj);
+    if (!instance.IsNull()) {
+      if (instance.IsValidNativeIndex(index)) {
+        *value = instance.GetNativeField(index);
+        return Api::Success();
+      }
+    } else {
+      is_null = true;
+    }
+  }
+  if (is_null) {
     RETURN_TYPE_ERROR(thread->zone(), obj, Instance);
   }
-  if (!instance.IsValidNativeIndex(index)) {
-    return Api::NewError(
-        "%s: invalid index %d passed in to access native instance field",
-        CURRENT_FUNC, index);
-  }
-  *value = instance.GetNativeField(index);
-  return Api::Success();
+  return Api::NewError(
+      "%s: invalid index %d passed in to access native instance field",
+      CURRENT_FUNC, index);
 }
 
 DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index da4f734..c454796 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5949,51 +5949,6 @@
   return static_cast<uint32_t>(v);
 }
 
-class CanonicalInstanceKey {
- public:
-  explicit CanonicalInstanceKey(const Instance& key) : key_(key) {
-    ASSERT(!(key.IsString() || key.IsAbstractType()));
-  }
-  bool Matches(const Instance& obj) const {
-    ASSERT(!(obj.IsString() || obj.IsAbstractType()));
-    if (key_.CanonicalizeEquals(obj)) {
-      ASSERT(obj.IsCanonical());
-      return true;
-    }
-    return false;
-  }
-  uword Hash() const { return key_.CanonicalizeHash(); }
-  const Instance& key_;
-
- private:
-  DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical Instances based on a hash of the fields.
-class CanonicalInstanceTraits {
- public:
-  static const char* Name() { return "CanonicalInstanceTraits"; }
-  static bool ReportStats() { return false; }
-
-  // Called when growing the table.
-  static bool IsMatch(const Object& a, const Object& b) {
-    ASSERT(!(a.IsString() || a.IsAbstractType()));
-    ASSERT(!(b.IsString() || b.IsAbstractType()));
-    return a.ptr() == b.ptr();
-  }
-  static bool IsMatch(const CanonicalInstanceKey& a, const Object& b) {
-    return a.Matches(Instance::Cast(b));
-  }
-  static uword Hash(const Object& key) {
-    ASSERT(!(key.IsString() || key.IsAbstractType()));
-    ASSERT(key.IsInstance());
-    return Instance::Cast(key).CanonicalizeHash();
-  }
-  static uword Hash(const CanonicalInstanceKey& key) { return key.Hash(); }
-  static ObjectPtr NewKey(const CanonicalInstanceKey& obj) {
-    return obj.key_.ptr();
-  }
-};
 typedef UnorderedHashSet<CanonicalInstanceTraits> CanonicalInstancesSet;
 
 InstancePtr Class::LookupCanonicalInstance(Zone* zone,
@@ -8109,7 +8064,11 @@
 }
 
 void Function::set_packed_fields(uint32_t packed_fields) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  UNREACHABLE();
+#else
   StoreNonPointer(&untag()->packed_fields_, packed_fields);
+#endif
 }
 
 bool Function::IsOptimizable() const {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index b5eaa99..19f2fd3 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3141,11 +3141,14 @@
   // Returns the size of the source for this function.
   intptr_t SourceSize() const;
 
-  uint32_t packed_fields() const { return untag()->packed_fields_; }
-  void set_packed_fields(uint32_t packed_fields) const;
-  static intptr_t packed_fields_offset() {
-    return OFFSET_OF(UntaggedFunction, packed_fields_);
+  uint32_t packed_fields() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+    UNREACHABLE();
+#else
+    return untag()->packed_fields_;
+#endif
   }
+  void set_packed_fields(uint32_t packed_fields) const;
 
   // Returns the number of required positional parameters.
   intptr_t num_fixed_parameters() const;
@@ -3881,11 +3884,19 @@
   //              some functions known to be execute infrequently and functions
   //              which have been de-optimized too many times.
   bool is_optimizable() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+    UNREACHABLE();
+#else
     return untag()->packed_fields_.Read<UntaggedFunction::PackedOptimizable>();
+#endif
   }
   void set_is_optimizable(bool value) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+    UNREACHABLE();
+#else
     untag()->packed_fields_.UpdateBool<UntaggedFunction::PackedOptimizable>(
         value);
+#endif
   }
 
   enum KindTagBits {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 6b5dab8..f490865 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1346,14 +1346,13 @@
   JIT_FUNCTION_COUNTERS(DECLARE)
 #undef DECLARE
 
-#endif  // !defined(DART_PRECOMPILED_RUNTIME)
-
   AtomicBitFieldContainer<uint8_t> packed_fields_;
 
   static constexpr intptr_t kMaxOptimizableBits = 1;
 
   using PackedOptimizable =
       BitField<decltype(packed_fields_), bool, 0, kMaxOptimizableBits>;
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
 };
 
 class UntaggedClosureData : public UntaggedObject {
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index 33b2332..d0d878c 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -320,19 +320,25 @@
 }
 
 StackZone::StackZone(ThreadState* thread)
+#if defined(DART_USE_ABSL)
+    // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading.
     : StackResource(thread), zone_(new Zone()) {
+#else
+    : StackResource(thread), zone_() {
+#endif  // defined(DART_USE_ABSL)
   if (FLAG_trace_zones) {
     OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
                  reinterpret_cast<intptr_t>(this),
-                 reinterpret_cast<intptr_t>(zone_));
+                 reinterpret_cast<intptr_t>(GetZone()));
   }
 
   // This thread must be preventing safepoints or the GC could be visiting the
   // chain of handle blocks we're about the mutate.
   ASSERT(Thread::Current()->MayAllocateHandles());
 
-  zone_->Link(thread->zone());
-  thread->set_zone(zone_);
+  Zone* lzone = GetZone();
+  lzone->Link(thread->zone());
+  thread->set_zone(lzone);
 }
 
 StackZone::~StackZone() {
@@ -340,15 +346,19 @@
   // chain of handle blocks we're about the mutate.
   ASSERT(Thread::Current()->MayAllocateHandles());
 
-  ASSERT(thread()->zone() == zone_);
-  thread()->set_zone(zone_->previous_);
+  Zone* lzone = GetZone();
+  ASSERT(thread()->zone() == lzone);
+  thread()->set_zone(lzone->previous_);
   if (FLAG_trace_zones) {
     OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n",
                  reinterpret_cast<intptr_t>(this),
-                 reinterpret_cast<intptr_t>(zone_));
+                 reinterpret_cast<intptr_t>(lzone));
   }
 
+#if defined(DART_USE_ABSL)
+  // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading.
   delete zone_;
+#endif  // defined(DART_USE_ABSL)
 }
 
 }  // namespace dart
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index a22f953..d5abb3b 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -192,6 +192,8 @@
   // Delete all memory associated with the zone.
   virtual ~StackZone();
 
+  // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading,
+#if defined(DART_USE_ABSL)
   // Compute the total size of this zone. This includes wasted space that is
   // due to internal fragmentation in the segments.
   uintptr_t SizeInBytes() const { return zone_->SizeInBytes(); }
@@ -200,9 +202,34 @@
   intptr_t CapacityInBytes() const { return zone_->CapacityInBytes(); }
 
   Zone* GetZone() { return zone_; }
+#else
+  // Compute the total size of this zone. This includes wasted space that is
+  // due to internal fragmentation in the segments.
+  uintptr_t SizeInBytes() const {
+    return zone_.SizeInBytes();
+  }
+
+  // Computes the used space in the zone.
+  intptr_t CapacityInBytes() const {
+    return zone_.CapacityInBytes();
+  }
+
+  Zone* GetZone() {
+    return &zone_;
+  }
+#endif  // defined(DART_USE_ABSL)
 
  private:
+#if defined(DART_USE_ABSL)
+  // When fibers are used we have to make do with a smaller stack size and hence
+  // the first zone is allocated instead of being a stack resource.
   Zone* zone_;
+#else
+  // For regular configurations that have larger stack sizes it is ok to
+  // have the first zone be a stack resource, avoids the overhead of a malloc
+  // call for every stack zone creation.
+  Zone zone_;
+#endif  // defined(DART_USE_ABSL)
 
   template <typename T>
   friend class GrowableArray;
diff --git a/tools/VERSION b/tools/VERSION
index 24622c4..33d92f0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 90
+PRERELEASE 91
 PRERELEASE_PATCH 0
\ No newline at end of file