Version 2.19.0-59.0.dev

Merge commit '409b426cfc7f23afe1035da4e594ddc412b6013d' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3e6dce..2038914 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -55,11 +55,17 @@
   non-final variable.
 - fix`use_build_context_synchronously` to handle `await`s in `if` conditions.
 
+### Core libraries
+
 #### `dart:io`
 
 - **Breaking Change** [#49305](https://github.com/dart-lang/sdk/issues/49305):
   Disallow negative or hexadecimal content-length headers.
 
+#### `dart:html`
+
+- Add constructor and `slice` to `SharedArrayBuffer`.
+
 ## 2.18.0
 
 ### Language
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 01507f9..1f37144 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -21,17 +21,17 @@
     for (var element in unitElement.classes) {
       await _computeForClassElement(element);
     }
-    for (var element in unitElement.enums) {
+    for (var element in unitElement.enums2) {
       await _computeForClassElement(element);
     }
-    for (var element in unitElement.mixins) {
+    for (var element in unitElement.mixins2) {
       await _computeForClassElement(element);
     }
   }
 
-  void _addImplementedClass(ClassElement type) {
-    var offset = type.nameOffset;
-    var length = type.nameLength;
+  void _addImplementedClass(InterfaceElement element) {
+    var offset = element.nameOffset;
+    var length = element.nameLength;
     classes.add(protocol.ImplementedClass(offset, length));
   }
 
@@ -50,9 +50,9 @@
     }
   }
 
-  Future<void> _computeForClassElement(ClassElement element) async {
+  Future<void> _computeForClassElement(InterfaceElement element) async {
     // Always include Object and its members.
-    if (element.supertype == null && !element.isMixin) {
+    if (element is ClassElement && element.isDartCoreObject) {
       _addImplementedClass(element);
       element.accessors.forEach(_addImplementedMember);
       element.fields.forEach(_addImplementedMember);
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine.dart b/pkg/analysis_server/lib/src/services/search/search_engine.dart
index 0b88104..850822d 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine.dart
@@ -49,7 +49,7 @@
   /// If the [type] has subtypes, return the set of names of members which these
   /// subtypes declare, possibly empty.  If the [type] does not have subtypes,
   /// return `null`.
-  Future<Set<String>?> membersOfSubtypes(ClassElement type);
+  Future<Set<String>?> membersOfSubtypes(InterfaceElement type);
 
   /// Returns all subtypes of the given [type].
   ///
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 2eda0d4..9ed9114 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -15,7 +15,7 @@
   SearchEngineImpl(this._drivers);
 
   @override
-  Future<Set<String>?> membersOfSubtypes(ClassElement type) async {
+  Future<Set<String>?> membersOfSubtypes(InterfaceElement type) async {
     var drivers = _drivers.toList();
     var searchedFiles = _createSearchedFiles(drivers);
 
@@ -24,7 +24,8 @@
     var visitedIds = <String>{};
     var members = <String>{};
 
-    Future<void> addMembers(ClassElement? type, SubtypeResult? subtype) async {
+    Future<void> addMembers(
+        InterfaceElement? type, SubtypeResult? subtype) async {
       if (subtype != null && !visitedIds.add(subtype.id)) {
         return;
       }
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index f602efc8..17610dd 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -17,6 +17,7 @@
 * Deprecated 'XyzDeclaration.name' in AST, use `name2` and `declaredElement` instead.
 * Deprecated `Element.enclosingElement2`, use `enclosingElement3` instead.  The meaningful change is that
   `ConstructorElement.enclosingElement3` returns now `IntefaceElement`, not `ClassElement`.
+* Deprecated `get enums/mixin`, use `get enums2/mixins2` instead.
 
 ## 4.3.1
 * Fix `identifier` for `LibraryExportElement` and `LibraryImportElement`.
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 3bfb26c..32230ff 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -3504,20 +3504,71 @@
   MethodElement? get staticElement;
 }
 
-/// The declaration of a mixin.
+/// The declaration of a mixin augmentation.
 ///
-///    mixinDeclaration ::=
-///        metadata? 'mixin' name [TypeParameterList]?
+///    mixinAugmentationDeclaration ::=
+///        'augment' 'mixin' name [TypeParameterList]?
 ///        [OnClause]? [ImplementsClause]? '{' [ClassMember]* '}'
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class MixinDeclaration implements ClassOrMixinDeclaration {
+@experimental
+abstract class MixinAugmentationDeclaration
+    implements MixinOrAugmentationDeclaration {
+  /// The token representing the 'augment' keyword.
+  Token get augmentKeyword;
+
+  @override
+  MixinAugmentationElement? get declaredElement;
+}
+
+/// The declaration of a mixin.
+///
+///    mixinDeclaration ::=
+///        'mixin' name [TypeParameterList]?
+///        [OnClause]? [ImplementsClause]? '{' [ClassMember]* '}'
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class MixinDeclaration
+    implements MixinOrAugmentationDeclaration, ClassOrMixinDeclaration {
+  // TODO(scheglov) Uncomment when removed [ClassOrMixinDeclaration].
+  // @override
+  // MixinElement get declaredElement;
+}
+
+/// Shared interface between [MixinDeclaration] and
+/// [MixinAugmentationDeclaration].
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class MixinOrAugmentationDeclaration
+    implements NamedCompilationUnitMember {
+  /// Returns the `implements` clause for the mixin, or `null` if the mixin
+  /// does not implement any interfaces.
+  ImplementsClause? get implementsClause;
+
+  // @override
+  // TODO(scheglov) Uncomment when removed [ClassOrMixinDeclaration].
+  // MixinOrAugmentationElement get declaredElement;
+
+  /// Returns the left curly bracket.
+  Token get leftBracket;
+
+  /// Returns the members defined by the mixin.
+  NodeList<ClassMember> get members;
+
   /// Return the token representing the 'mixin' keyword.
   Token get mixinKeyword;
 
   /// Return the on clause for the mixin, or `null` if the mixin does not have
   /// any superclass constraints.
   OnClause? get onClause;
+
+  /// Returns the right curly bracket.
+  Token get rightBracket;
+
+  /// Returns the type parameters for the mixin, or `null` if the mixin does
+  /// not have any type parameters.
+  TypeParameterList? get typeParameters;
 }
 
 /// A node that declares a single name within the scope of a compilation unit.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 8305498..76ea504 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -273,8 +273,13 @@
 
   /// Return a list containing all of the enums contained in this compilation
   /// unit.
+  @Deprecated('Use enums2 instead')
   List<ClassElement> get enums;
 
+  /// Return a list containing all of the enums contained in this compilation
+  /// unit.
+  List<EnumElement> get enums2;
+
   /// Return a list containing all of the extensions contained in this
   /// compilation unit.
   List<ExtensionElement> get extensions;
@@ -288,8 +293,13 @@
 
   /// Return a list containing all of the mixins contained in this compilation
   /// unit.
+  @Deprecated('Use mixins2 instead')
   List<ClassElement> get mixins;
 
+  /// Return a list containing all of the mixins contained in this compilation
+  /// unit.
+  List<MixinElement> get mixins2;
+
   @override
   AnalysisSession get session;
 
@@ -304,8 +314,14 @@
   /// Return the enum defined in this compilation unit that has the given
   /// [name], or `null` if this compilation unit does not define an enum with
   /// the given name.
+  @Deprecated('Use getEnum2() instead')
   ClassElement? getEnum(String name);
 
+  /// Return the enum defined in this compilation unit that has the given
+  /// [name], or `null` if this compilation unit does not define an enum with
+  /// the given name.
+  EnumElement? getEnum2(String name);
+
   /// Return the class defined in this compilation unit that has the given
   /// [name], or `null` if this compilation unit does not define a class with
   /// the given name.
@@ -1010,6 +1026,8 @@
 
   R? visitConstructorElement(ConstructorElement element);
 
+  R? visitEnumElement(EnumElement element);
+
   @Deprecated('Override visitLibraryExportElement() instead')
   R? visitExportElement(ExportElement element);
 
@@ -1040,6 +1058,8 @@
 
   R? visitMethodElement(MethodElement element);
 
+  R? visitMixinElement(MixinElement element);
+
   R? visitMultiplyDefinedElement(MultiplyDefinedElement element);
 
   R? visitParameterElement(ParameterElement element);
@@ -1394,12 +1414,94 @@
   /// library.
   InterfaceType get thisType;
 
+  /// Returns the unnamed constructor declared directly in this class. If the
+  /// class does not declare any constructors, a synthetic default constructor
+  /// will be returned.
+  /// TODO(scheglov) Deprecate and remove it.
+  ConstructorElement? get unnamedConstructor;
+
+  /// Returns the field (synthetic or explicit) defined directly in this
+  /// class or augmentation that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  FieldElement? getField(String name);
+
+  /// Returns the getter (synthetic or explicit) defined directly in this
+  /// class or augmentation that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? getGetter(String name);
+
+  /// Returns the method defined directly in this class or augmentation that
+  /// has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? getMethod(String name);
+
+  /// Returns the constructor defined directly in this class or augmentation
+  /// that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  ConstructorElement? getNamedConstructor(String name);
+
+  /// Returns the setter (synthetic or explicit) defined directly in this
+  /// class or augmentation that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? getSetter(String name);
+
   /// Create the [InterfaceType] for this element with the given [typeArguments]
   /// and [nullabilitySuffix].
   InterfaceType instantiate({
     required List<DartType> typeArguments,
     required NullabilitySuffix nullabilitySuffix,
   });
+
+  /// Return the element representing the getter that results from looking up
+  /// the given [getterName] in this class with respect to the given [library],
+  /// or `null` if the look up fails. The behavior of this method is defined by
+  /// the Dart Language Specification in section 16.15.2:
+  /// <blockquote>
+  /// The result of looking up getter (respectively setter) <i>m</i> in class
+  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
+  /// instance getter (respectively setter) named <i>m</i> that is accessible to
+  /// <i>L</i>, then that getter (respectively setter) is the result of the
+  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
+  /// of the lookup is the result of looking up getter (respectively setter)
+  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
+  /// lookup has failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? lookUpGetter(
+      String getterName, LibraryElement library);
+
+  /// Return the element representing the method that results from looking up
+  /// the given [methodName] in the superclass of this class with respect to the
+  /// given [library], or `null` if the look up fails. The behavior of this
+  /// method is defined by the Dart Language Specification in section 16.15.1:
+  /// <blockquote>
+  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
+  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
+  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
+  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
+  /// result of the lookup is the result of looking up method <i>m</i> in
+  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
+  /// failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? lookUpInheritedMethod(
+      String methodName, LibraryElement library);
+
+  /// Return the element representing the method that results from looking up
+  /// the given [methodName] in this class with respect to the given [library],
+  /// or `null` if the look up fails. The behavior of this method is defined by
+  /// the Dart Language Specification in section 16.15.1:
+  /// <blockquote>
+  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
+  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
+  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
+  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
+  /// result of the lookup is the result of looking up method <i>m</i> in
+  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
+  /// failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? lookUpMethod(String methodName, LibraryElement library);
 }
 
 /// Shared interface between [InterfaceElement] and augmentations.
@@ -2402,37 +2504,6 @@
   /// guard against infinite loops.
   InterfaceType? get supertype;
 
-  /// Returns the unnamed constructor declared directly in this class. If the
-  /// class does not declare any constructors, a synthetic default constructor
-  /// will be returned.
-  /// TODO(scheglov) Deprecate and remove it.
-  ConstructorElement? get unnamedConstructor;
-
-  /// Returns the field (synthetic or explicit) defined directly in this
-  /// class or augmentation that has the given [name].
-  /// TODO(scheglov) Deprecate and remove it.
-  FieldElement? getField(String name);
-
-  /// Returns the getter (synthetic or explicit) defined directly in this
-  /// class or augmentation that has the given [name].
-  /// TODO(scheglov) Deprecate and remove it.
-  PropertyAccessorElement? getGetter(String name);
-
-  /// Returns the method defined directly in this class or augmentation that
-  /// has the given [name].
-  /// TODO(scheglov) Deprecate and remove it.
-  MethodElement? getMethod(String name);
-
-  /// Returns the constructor defined directly in this class or augmentation
-  /// that has the given [name].
-  /// TODO(scheglov) Deprecate and remove it.
-  ConstructorElement? getNamedConstructor(String name);
-
-  /// Returns the setter (synthetic or explicit) defined directly in this
-  /// class or augmentation that has the given [name].
-  /// TODO(scheglov) Deprecate and remove it.
-  PropertyAccessorElement? getSetter(String name);
-
   /// Return the element representing the method that results from looking up
   /// the given [methodName] in this class with respect to the given [library],
   /// ignoring abstract methods, or `null` if the look up fails. The behavior of
@@ -2452,24 +2523,6 @@
       String methodName, LibraryElement library);
 
   /// Return the element representing the getter that results from looking up
-  /// the given [getterName] in this class with respect to the given [library],
-  /// or `null` if the look up fails. The behavior of this method is defined by
-  /// the Dart Language Specification in section 16.15.2:
-  /// <blockquote>
-  /// The result of looking up getter (respectively setter) <i>m</i> in class
-  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
-  /// instance getter (respectively setter) named <i>m</i> that is accessible to
-  /// <i>L</i>, then that getter (respectively setter) is the result of the
-  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
-  /// of the lookup is the result of looking up getter (respectively setter)
-  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
-  /// lookup has failed.
-  /// </blockquote>
-  /// TODO(scheglov) Deprecate and remove it.
-  PropertyAccessorElement? lookUpGetter(
-      String getterName, LibraryElement library);
-
-  /// Return the element representing the getter that results from looking up
   /// the given [getterName] in the superclass of this class with respect to the
   /// given [library], ignoring abstract getters, or `null` if the look up
   /// fails.  The behavior of this method is defined by the Dart Language
@@ -2525,39 +2578,6 @@
   PropertyAccessorElement? lookUpInheritedConcreteSetter(
       String setterName, LibraryElement library);
 
-  /// Return the element representing the method that results from looking up
-  /// the given [methodName] in the superclass of this class with respect to the
-  /// given [library], or `null` if the look up fails. The behavior of this
-  /// method is defined by the Dart Language Specification in section 16.15.1:
-  /// <blockquote>
-  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
-  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
-  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
-  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
-  /// result of the lookup is the result of looking up method <i>m</i> in
-  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
-  /// failed.
-  /// </blockquote>
-  /// TODO(scheglov) Deprecate and remove it.
-  MethodElement? lookUpInheritedMethod(
-      String methodName, LibraryElement library);
-
-  /// Return the element representing the method that results from looking up
-  /// the given [methodName] in this class with respect to the given [library],
-  /// or `null` if the look up fails. The behavior of this method is defined by
-  /// the Dart Language Specification in section 16.15.1:
-  /// <blockquote>
-  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
-  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
-  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
-  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
-  /// result of the lookup is the result of looking up method <i>m</i> in
-  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
-  /// failed.
-  /// </blockquote>
-  /// TODO(scheglov) Deprecate and remove it.
-  MethodElement? lookUpMethod(String methodName, LibraryElement library);
-
   /// Return the element representing the setter that results from looking up
   /// the given [setterName] in this class with respect to the given [library],
   /// or `null` if the look up fails. The behavior of this method is defined by
diff --git a/pkg/analyzer/lib/dart/element/visitor.dart b/pkg/analyzer/lib/dart/element/visitor.dart
index 2ec106e..c5de555 100644
--- a/pkg/analyzer/lib/dart/element/visitor.dart
+++ b/pkg/analyzer/lib/dart/element/visitor.dart
@@ -102,6 +102,9 @@
     return null;
   }
 
+  @override
+  R? visitEnumElement(EnumElement element) => visitElement(element);
+
   R? visitExecutableElement(ExecutableElement element) => visitElement(element);
 
   @Deprecated('Override visitLibraryExportElement() instead')
@@ -169,6 +172,9 @@
       visitExecutableElement(element);
 
   @override
+  R? visitMixinElement(MixinElement element) => visitElement(element);
+
+  @override
   R? visitMultiplyDefinedElement(MultiplyDefinedElement element) =>
       visitElement(element);
 
@@ -246,6 +252,12 @@
     return null;
   }
 
+  @override
+  R? visitEnumElement(EnumElement element) {
+    element.visitChildren(this);
+    return null;
+  }
+
   @Deprecated('Override visitLibraryExportElement() instead')
   @override
   R? visitExportElement(ExportElement element) {
@@ -333,6 +345,12 @@
   }
 
   @override
+  R? visitMixinElement(MixinElement element) {
+    element.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitMultiplyDefinedElement(MultiplyDefinedElement element) {
     element.visitChildren(this);
     return null;
@@ -409,6 +427,9 @@
   @override
   R? visitConstructorElement(ConstructorElement element) => null;
 
+  @override
+  R? visitEnumElement(EnumElement element) => null;
+
   @Deprecated('Override visitLibraryExportElement() instead')
   @override
   R? visitExportElement(ExportElement element) => null;
@@ -457,6 +478,9 @@
   R? visitMethodElement(MethodElement element) => null;
 
   @override
+  R? visitMixinElement(MixinElement element) => null;
+
+  @override
   R? visitMultiplyDefinedElement(MultiplyDefinedElement element) => null;
 
   @override
@@ -510,6 +534,9 @@
   @override
   R? visitConstructorElement(ConstructorElement element) => _throw(element);
 
+  @override
+  R? visitEnumElement(EnumElement element) => _throw(element);
+
   @Deprecated('Override visitLibraryExportElement() instead')
   @override
   R? visitExportElement(ExportElement element) => _throw(element);
@@ -558,6 +585,9 @@
   R? visitMethodElement(MethodElement element) => _throw(element);
 
   @override
+  R? visitMixinElement(MixinElement element) => _throw(element);
+
+  @override
   R? visitMultiplyDefinedElement(MultiplyDefinedElement element) =>
       _throw(element);
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index 749d2b6..6a385ff 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -206,7 +206,7 @@
       }
     }
 
-    void addElements(ClassElement element) {
+    void addElements(InterfaceElement element) {
       element.accessors.forEach(addElement);
       element.fields.forEach(addElement);
       element.methods.forEach(addElement);
@@ -218,8 +218,8 @@
         var unitResult = await _driver.getUnitElement(file);
         if (unitResult is UnitElementResult) {
           unitResult.element.classes.forEach(addElements);
-          unitResult.element.enums.forEach(addElements);
-          unitResult.element.mixins.forEach(addElements);
+          unitResult.element.enums2.forEach(addElements);
+          unitResult.element.mixins2.forEach(addElements);
         }
       }
     }
@@ -301,7 +301,7 @@
 
   /// Return direct [SubtypeResult]s for either the [type] or [subtype].
   Future<List<SubtypeResult>> subtypes(SearchedFiles searchedFiles,
-      {ClassElement? type, SubtypeResult? subtype}) async {
+      {InterfaceElement? type, SubtypeResult? subtype}) async {
     String name;
     String id;
     if (type != null) {
@@ -351,10 +351,10 @@
         CompilationUnitElement unitElement = unitResult.element;
         unitElement.accessors.forEach(addElement);
         unitElement.classes.forEach(addElement);
-        unitElement.enums.forEach(addElement);
+        unitElement.enums2.forEach(addElement);
         unitElement.extensions.forEach(addElement);
         unitElement.functions.forEach(addElement);
-        unitElement.mixins.forEach(addElement);
+        unitElement.mixins2.forEach(addElement);
         unitElement.topLevelVariables.forEach(addElement);
         unitElement.typeAliases.forEach(addElement);
       }
@@ -881,7 +881,7 @@
     }
   }
 
-  void _addClasses(FileState file, List<ClassElement> elements) {
+  void _addClasses(FileState file, List<InterfaceElement> elements) {
     for (var i = 0; i < elements.length; i++) {
       var element = elements[i];
       _addDeclaration(file, element, element.name);
@@ -1012,8 +1012,8 @@
       var element = elements[i];
       _addAccessors(file, element.accessors);
       _addClasses(file, element.classes);
-      _addClasses(file, element.enums);
-      _addClasses(file, element.mixins);
+      _addClasses(file, element.enums2);
+      _addClasses(file, element.mixins2);
       _addExtensions(file, element.extensions);
       _addFunctions(file, element.functions);
       _addTypeAliases(file, element.typeAliases);
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 35324b3..bd5a985 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -226,8 +226,17 @@
   ///
   /// Note that type arguments are only valid if [Feature.generic_metadata] is
   /// enabled.
-  AnnotationImpl(this.atSign, this._name, this._typeArguments, this.period,
-      this._constructorName, this._arguments) {
+  AnnotationImpl({
+    required this.atSign,
+    required IdentifierImpl name,
+    required TypeArgumentListImpl? typeArguments,
+    required this.period,
+    required SimpleIdentifierImpl? constructorName,
+    required ArgumentListImpl? arguments,
+  })  : _name = name,
+        _typeArguments = typeArguments,
+        _constructorName = constructorName,
+        _arguments = arguments {
     _becomeParentOf(_name);
     _becomeParentOf(_typeArguments);
     _becomeParentOf(_constructorName);
@@ -1105,7 +1114,11 @@
   /// statements. The [keyword] can be `null` if there is no keyword specified
   /// for the block. The [star] can be `null` if there is no star following the
   /// keyword (and must be `null` if there is no keyword).
-  BlockFunctionBodyImpl(this.keyword, this.star, this._block) {
+  BlockFunctionBodyImpl({
+    required this.keyword,
+    required this.star,
+    required BlockImpl block,
+  }) : _block = block {
     _becomeParentOf(_block);
   }
 
@@ -1172,7 +1185,11 @@
   Token rightBracket;
 
   /// Initialize a newly created block of code.
-  BlockImpl(this.leftBracket, List<Statement> statements, this.rightBracket) {
+  BlockImpl({
+    required this.leftBracket,
+    required List<Statement> statements,
+    required this.rightBracket,
+  }) {
     _statements._initialize(this, statements);
   }
 
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 78a09e7..2b88c05 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -15,32 +15,9 @@
 final AstFactoryImpl astFactory = AstFactoryImpl();
 
 class AstFactoryImpl {
-  AnnotationImpl annotation(
-          {required Token atSign,
-          required Identifier name,
-          TypeArgumentList? typeArguments,
-          Token? period,
-          SimpleIdentifier? constructorName,
-          ArgumentList? arguments}) =>
-      AnnotationImpl(
-          atSign,
-          name as IdentifierImpl,
-          typeArguments as TypeArgumentListImpl?,
-          period,
-          constructorName as SimpleIdentifierImpl?,
-          arguments as ArgumentListImpl?);
-
-  BlockImpl block(
-          Token leftBracket, List<Statement> statements, Token rightBracket) =>
-      BlockImpl(leftBracket, statements, rightBracket);
-
   CommentImpl blockComment(List<Token> tokens) =>
       CommentImpl.createBlockComment(tokens);
 
-  BlockFunctionBodyImpl blockFunctionBody(
-          Token? keyword, Token? star, Block block) =>
-      BlockFunctionBodyImpl(keyword, star, block as BlockImpl);
-
   BooleanLiteralImpl booleanLiteral(Token literal, bool value) =>
       BooleanLiteralImpl(literal, value);
 
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index cd1e068..0c9653e 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1089,7 +1089,7 @@
   List<ClassElement> _classes = const [];
 
   /// A list containing all of the enums contained in this compilation unit.
-  List<ClassElement> _enums = const [];
+  List<EnumElement> _enums = const [];
 
   /// A list containing all of the extensions contained in this compilation
   /// unit.
@@ -1100,7 +1100,7 @@
   List<FunctionElement> _functions = const [];
 
   /// A list containing all of the mixins contained in this compilation unit.
-  List<ClassElement> _mixins = const [];
+  List<MixinElement> _mixins = const [];
 
   /// A list containing all of the type aliases contained in this compilation
   /// unit.
@@ -1171,15 +1171,21 @@
     return this;
   }
 
+  @Deprecated('Use enums2 instead')
   @override
   List<ClassElement> get enums {
+    return _enums.map((e) => e as ClassElement).toList();
+  }
+
+  @override
+  List<EnumElement> get enums2 {
     return _enums;
   }
 
   /// Set the enums contained in this compilation unit to the given [enums].
-  set enums(List<ClassElement> enums) {
-    for (ClassElement enumDeclaration in enums) {
-      (enumDeclaration as EnumElementImpl).enclosingElement = this;
+  set enums2(List<EnumElement> enums) {
+    for (final element in enums) {
+      (element as EnumElementImpl).enclosingElement = this;
     }
     _enums = enums;
   }
@@ -1227,13 +1233,19 @@
     return super.metadata;
   }
 
+  @Deprecated('Use mixins2 instead')
   @override
   List<ClassElement> get mixins {
+    return _mixins.map((e) => e as ClassElement).toList();
+  }
+
+  @override
+  List<MixinElement> get mixins2 {
     return _mixins;
   }
 
   /// Set the mixins contained in this compilation unit to the given [mixins].
-  set mixins(List<ClassElement> mixins) {
+  set mixins2(List<MixinElement> mixins) {
     for (var type in mixins) {
       (type as MixinElementImpl).enclosingElement = this;
     }
@@ -1286,6 +1298,7 @@
     builder.writeCompilationUnitElement(this);
   }
 
+  @Deprecated('Use getEnum2() instead')
   @override
   ClassElement? getEnum(String enumName) {
     for (ClassElement enumDeclaration in enums) {
@@ -1297,6 +1310,16 @@
   }
 
   @override
+  EnumElement? getEnum2(String name) {
+    for (final element in enums2) {
+      if (element.name == name) {
+        return element;
+      }
+    }
+    return null;
+  }
+
+  @override
   ClassElement? getType(String className) {
     for (ClassElement class_ in classes) {
       if (class_.name == className) {
@@ -1318,10 +1341,10 @@
     super.visitChildren(visitor);
     safelyVisitChildren(accessors, visitor);
     safelyVisitChildren(classes, visitor);
-    safelyVisitChildren(enums, visitor);
+    safelyVisitChildren(enums2, visitor);
     safelyVisitChildren(extensions, visitor);
     safelyVisitChildren(functions, visitor);
-    safelyVisitChildren(mixins, visitor);
+    safelyVisitChildren(mixins2, visitor);
     safelyVisitChildren(typeAliases, visitor);
     safelyVisitChildren(topLevelVariables, visitor);
   }
@@ -3038,6 +3061,12 @@
   }
 
   @override
+  T? accept<T>(ElementVisitor<T> visitor) {
+    visitor.visitClassElement(this);
+    return visitor.visitEnumElement(this);
+  }
+
+  @override
   void appendTo(ElementDisplayStringBuilder builder) {
     builder.writeEnumElement(this);
   }
@@ -4284,10 +4313,10 @@
     for (var unit in units) {
       yield* unit.accessors;
       yield* unit.classes;
-      yield* unit.enums;
+      yield* unit.enums2;
       yield* unit.extensions;
       yield* unit.functions;
-      yield* unit.mixins;
+      yield* unit.mixins2;
       yield* unit.topLevelVariables;
       yield* unit.typeAliases;
     }
@@ -4323,9 +4352,9 @@
           ..returnType = typeProvider.futureDynamicType;
   }
 
-  ClassElement? getEnum(String name) {
+  EnumElement? getEnum(String name) {
     for (final unitElement in units) {
-      final element = unitElement.getEnum(name);
+      final element = unitElement.getEnum2(name);
       if (element != null) {
         return element;
       }
@@ -4948,6 +4977,12 @@
   }
 
   @override
+  T? accept<T>(ElementVisitor<T> visitor) {
+    visitor.visitClassElement(this);
+    return visitor.visitMixinElement(this);
+  }
+
+  @override
   void appendTo(ElementDisplayStringBuilder builder) {
     builder.writeMixinElement(this);
   }
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index ad86fb1..84d0ae4 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -47,18 +47,18 @@
       Name(null, FunctionElement.NO_SUCH_METHOD_METHOD_NAME);
 
   /// Cached instance interfaces for [ClassElement].
-  final Map<ClassElement, Interface> _interfaces = {};
+  final Map<InterfaceElement, Interface> _interfaces = {};
 
   /// The set of classes that are currently being processed, used to detect
   /// self-referencing cycles.
-  final Set<ClassElement> _processingClasses = <ClassElement>{};
+  final Set<InterfaceElement> _processingClasses = {};
 
   /// Combine [candidates] into a single signature in the [targetClass].
   ///
   /// If such signature does not exist, return `null`, and if [conflicts] is
   /// not `null`, add a new [Conflict] to it.
   ExecutableElement? combineSignatures({
-    required ClassElement targetClass,
+    required InterfaceElement targetClass,
     required List<ExecutableElement> candidates,
     required bool doTopMerge,
     required Name name,
@@ -132,7 +132,7 @@
   /// at all, or because there is no the most specific signature.
   ///
   /// This is equivalent to `getInheritedMap2(type)[name]`.
-  ExecutableElement? getInherited2(ClassElement element, Name name) {
+  ExecutableElement? getInherited2(InterfaceElement element, Name name) {
     return getInheritedMap2(element)[name];
   }
 
@@ -156,7 +156,8 @@
 
   /// Return signatures of all concrete members that the given [element] inherits
   /// from the superclasses and mixins.
-  Map<Name, ExecutableElement> getInheritedConcreteMap2(ClassElement element) {
+  Map<Name, ExecutableElement> getInheritedConcreteMap2(
+      InterfaceElement element) {
     var interface = getInterface(element);
     return interface._superImplemented.last;
   }
@@ -185,7 +186,7 @@
   /// inherited from the super-interfaces (superclasses, mixins, and
   /// interfaces).  If there is no most specific signature for a name, the
   /// corresponding name will not be included.
-  Map<Name, ExecutableElement> getInheritedMap2(ClassElement element) {
+  Map<Name, ExecutableElement> getInheritedMap2(InterfaceElement element) {
     var interface = getInterface(element);
     var inheritedMap = interface._inheritedMap;
     if (inheritedMap == null) {
@@ -202,7 +203,7 @@
 
   /// Return the interface of the given [element].  It might include
   /// private members, not necessary accessible in all libraries.
-  Interface getInterface(ClassElement element) {
+  Interface getInterface(InterfaceElement element) {
     var result = _interfaces[element];
     if (result != null) {
       return result;
@@ -214,7 +215,7 @@
     }
 
     try {
-      if (element.isMixin) {
+      if (element is MixinElement) {
         result = _getInterfaceMixin(element);
       } else {
         result = _getInterfaceClass(element);
@@ -262,7 +263,7 @@
   /// given number of mixins after it are considered.  For example for `1` in
   /// `class C extends S with M1, M2, M3`, only `S` and `M1` are considered.
   ExecutableElement? getMember2(
-    ClassElement element,
+    InterfaceElement element,
     Name name, {
     bool concrete = false,
     int forMixinIndex = -1,
@@ -339,7 +340,7 @@
 
   void _addImplemented(
     Map<Name, ExecutableElement> implemented,
-    ClassElement element,
+    InterfaceElement element,
   ) {
     var libraryUri = element.librarySource.uri;
 
@@ -413,7 +414,7 @@
   /// such single most specific signature (i.e. no valid override), then add a
   /// new conflict description.
   List<Conflict> _findMostSpecificFromNamedCandidates(
-    ClassElement targetClass,
+    InterfaceElement targetClass,
     Map<Name, ExecutableElement> map,
     Map<Name, List<ExecutableElement>> namedCandidates, {
     required bool doTopMerge,
@@ -445,7 +446,7 @@
     return conflicts;
   }
 
-  Interface _getInterfaceClass(ClassElement element) {
+  Interface _getInterfaceClass(InterfaceElement element) {
     var classLibrary = element.library;
     var isNonNullableByDefault = classLibrary.isNonNullableByDefault;
 
@@ -453,8 +454,16 @@
     var superImplemented = <Map<Name, ExecutableElement>>[];
     var implemented = <Name, ExecutableElement>{};
 
+    final InterfaceType? superType;
+    if (element is ClassElement) {
+      superType = element.supertype;
+    } else if (element is EnumElement) {
+      superType = element.supertype;
+    } else {
+      throw UnimplementedError('(${element.runtimeType}) $element');
+    }
+
     Interface? superTypeInterface;
-    var superType = element.supertype;
     if (superType != null) {
       var substitution = Substitution.fromInterfaceType(superType);
       superTypeInterface = getInterface(superType.element);
@@ -601,7 +610,7 @@
     );
 
     var noSuchMethodForwarders = <Name>{};
-    if (element.isAbstract) {
+    if (element is ClassElement && element.isAbstract) {
       if (superTypeInterface != null) {
         noSuchMethodForwarders = superTypeInterface._noSuchMethodForwarders;
       }
@@ -644,7 +653,7 @@
     );
   }
 
-  Interface _getInterfaceMixin(ClassElement element) {
+  Interface _getInterfaceMixin(MixinElement element) {
     var classLibrary = element.library;
     var isNonNullableByDefault = classLibrary.isNonNullableByDefault;
 
@@ -709,7 +718,7 @@
   /// covariant. If there are no covariant parameters, or parameters to
   /// update are already covariant, return the [executable] itself.
   ExecutableElement _inheritCovariance(
-    ClassElement class_,
+    InterfaceElement class_,
     Map<Name, List<ExecutableElement>> namedCandidates,
     Name name,
     ExecutableElement executable,
@@ -804,7 +813,7 @@
   /// signature. This signature always exists.
   ExecutableElement _topMerge(
     TypeSystemImpl typeSystem,
-    ClassElement targetClass,
+    InterfaceElement targetClass,
     List<ExecutableElement> validOverrides,
   ) {
     var first = validOverrides[0];
@@ -876,7 +885,9 @@
     }
   }
 
-  static Map<Name, ExecutableElement> _getTypeMembers(ClassElement element) {
+  static Map<Name, ExecutableElement> _getTypeMembers(
+    InterfaceElement element,
+  ) {
     var declared = <Name, ExecutableElement>{};
     var libraryUri = element.librarySource.uri;
 
diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart
index 679e477..7e1f1e7 100644
--- a/pkg/analyzer/lib/src/dart/element/scope.dart
+++ b/pkg/analyzer/lib/src/dart/element/scope.dart
@@ -139,11 +139,11 @@
 
   void _addUnitElements(CompilationUnitElement compilationUnit) {
     compilationUnit.accessors.forEach(_addPropertyAccessor);
-    compilationUnit.enums.forEach(_addGetter);
+    compilationUnit.enums2.forEach(_addGetter);
     compilationUnit.extensions.forEach(_addExtension);
     compilationUnit.functions.forEach(_addGetter);
     compilationUnit.typeAliases.forEach(_addGetter);
-    compilationUnit.mixins.forEach(_addGetter);
+    compilationUnit.mixins2.forEach(_addGetter);
     compilationUnit.classes.forEach(_addGetter);
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index b91660b..9249da9 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -211,7 +211,7 @@
     for (ClassElement element in compilationUnit.classes) {
       _addIfPublic(definedNames, element);
     }
-    for (ClassElement element in compilationUnit.enums) {
+    for (final element in compilationUnit.enums2) {
       _addIfPublic(definedNames, element);
     }
     for (ExtensionElement element in compilationUnit.extensions) {
@@ -220,7 +220,7 @@
     for (FunctionElement element in compilationUnit.functions) {
       _addIfPublic(definedNames, element);
     }
-    for (ClassElement element in compilationUnit.mixins) {
+    for (final element in compilationUnit.mixins2) {
       _addIfPublic(definedNames, element);
     }
     for (TypeAliasElement element in compilationUnit.typeAliases) {
diff --git a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
index 3afd901..991084b 100644
--- a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
+++ b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
@@ -314,7 +314,7 @@
       for (ClassElement class_ in element.classes) {
         definedGetters[class_.name] = class_;
       }
-      for (ClassElement type in element.enums) {
+      for (final type in element.enums2) {
         definedGetters[type.name] = type;
       }
       for (FunctionElement function in element.functions) {
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 4523131..f0ab1d9 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -786,7 +786,13 @@
     debugEvent("Block");
 
     var statements = popTypedList2<Statement>(count);
-    push(ast.block(leftBracket, statements, rightBracket));
+    push(
+      BlockImpl(
+        leftBracket: leftBracket,
+        statements: statements,
+        rightBracket: rightBracket,
+      ),
+    );
   }
 
   @override
@@ -796,11 +802,21 @@
     debugEvent("BlockFunctionBody");
 
     var statements = popTypedList2<Statement>(count);
-    Block block = ast.block(leftBracket, statements, rightBracket);
+    final block = BlockImpl(
+      leftBracket: leftBracket,
+      statements: statements,
+      rightBracket: rightBracket,
+    );
     var star = pop() as Token?;
     var asyncKeyword = pop() as Token?;
     if (parseFunctionBodies) {
-      push(ast.blockFunctionBody(asyncKeyword, star, block));
+      push(
+        BlockFunctionBodyImpl(
+          keyword: asyncKeyword,
+          star: star,
+          block: block,
+        ),
+      );
     } else {
       // TODO(danrubel): Skip the block rather than parsing it.
       push(ast.emptyFunctionBody(
@@ -2112,10 +2128,10 @@
     assert(optionalOrNull('.', periodBeforeName));
     debugEvent("Metadata");
 
-    var invocation = pop() as MethodInvocation?;
+    var invocation = pop() as MethodInvocationImpl?;
     var constructorName =
-        periodBeforeName != null ? pop() as SimpleIdentifier : null;
-    var typeArguments = pop() as TypeArgumentList?;
+        periodBeforeName != null ? pop() as SimpleIdentifierImpl : null;
+    var typeArguments = pop() as TypeArgumentListImpl?;
     if (typeArguments != null &&
         !_featureSet.isEnabled(Feature.generic_metadata)) {
       _reportFeatureNotEnabled(
@@ -2123,14 +2139,17 @@
         startToken: typeArguments.beginToken,
       );
     }
-    var name = pop() as Identifier;
-    push(ast.annotation(
+    var name = pop() as IdentifierImpl;
+    push(
+      AnnotationImpl(
         atSign: atSign,
         name: name,
         typeArguments: typeArguments,
         period: periodBeforeName,
         constructorName: constructorName,
-        arguments: invocation?.argumentList));
+        arguments: invocation?.argumentList,
+      ),
+    );
   }
 
   @override
@@ -3493,10 +3512,20 @@
     assert(optional('{', leftBracket));
     assert(optional('}', leftBracket.endGroup!));
     debugEvent("InvalidFunctionBody");
-    Block block = ast.block(leftBracket, [], leftBracket.endGroup!);
+    final block = BlockImpl(
+      leftBracket: leftBracket,
+      statements: [],
+      rightBracket: leftBracket.endGroup!,
+    );
     var star = pop() as Token?;
     var asyncKeyword = pop() as Token?;
-    push(ast.blockFunctionBody(asyncKeyword, star, block));
+    push(
+      BlockFunctionBodyImpl(
+        keyword: asyncKeyword,
+        star: star,
+        block: block,
+      ),
+    );
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 5768e84..751f6ca 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -151,7 +151,7 @@
   void visitConstructorFieldInitializer(
       covariant ConstructorFieldInitializerImpl node) {
     var fieldName = node.fieldName;
-    ClassElement enclosingClass = _resolver.enclosingClass!;
+    final enclosingClass = _resolver.enclosingClass!;
     var fieldElement = enclosingClass.getField(fieldName.name);
     fieldName.staticElement = fieldElement;
   }
@@ -302,7 +302,7 @@
   void visitRedirectingConstructorInvocation(
       covariant RedirectingConstructorInvocationImpl node) {
     var enclosingClass = _resolver.enclosingClass;
-    if (enclosingClass == null) {
+    if (enclosingClass is! ClassElement) {
       // TODO(brianwilkerson) Report this error.
       return;
     }
@@ -336,7 +336,7 @@
   void visitSuperConstructorInvocation(
       covariant SuperConstructorInvocationImpl node) {
     var enclosingClass = _resolver.enclosingClass;
-    if (enclosingClass == null) {
+    if (enclosingClass is! ClassElement) {
       // TODO(brianwilkerson) Report this error.
       return;
     }
diff --git a/pkg/analyzer/lib/src/generated/element_walker.dart b/pkg/analyzer/lib/src/generated/element_walker.dart
index aafabade..35f4f3a 100644
--- a/pkg/analyzer/lib/src/generated/element_walker.dart
+++ b/pkg/analyzer/lib/src/generated/element_walker.dart
@@ -19,13 +19,13 @@
   int _classIndex = 0;
   List<ConstructorElement>? _constructors;
   int _constructorIndex = 0;
-  List<ClassElement>? _enums;
+  List<EnumElement>? _enums;
   int _enumIndex = 0;
   List<ExtensionElement>? _extensions;
   int _extensionIndex = 0;
   List<ExecutableElement>? _functions;
   int _functionIndex = 0;
-  List<ClassElement>? _mixins;
+  List<MixinElement>? _mixins;
   int _mixinIndex = 0;
   List<ParameterElement>? _parameters;
   int _parameterIndex = 0;
@@ -53,10 +53,10 @@
       {this.libraryFilePath, this.unitFilePath})
       : _accessors = element.accessors.where(_isNotSynthetic).toList(),
         _classes = element.classes,
-        _enums = element.enums,
+        _enums = element.enums2,
         _extensions = element.extensions,
         _functions = element.functions,
-        _mixins = element.mixins,
+        _mixins = element.mixins2,
         _typedefs = element.typeAliases,
         _variables = element.topLevelVariables.where(_isNotSynthetic).toList();
 
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index ce5307a..f8c23a9 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -143,7 +143,7 @@
 
   /// The class containing the AST nodes being visited,
   /// or `null` if we are not in the scope of a class.
-  ClassElement? enclosingClass;
+  InterfaceElement? enclosingClass;
 
   /// The element representing the extension containing the AST nodes being
   /// visited, or `null` if we are not in the scope of an extension.
@@ -716,7 +716,7 @@
 
   /// Set information about enclosing declarations.
   void prepareEnclosingDeclarations({
-    ClassElement? enclosingClassElement,
+    InterfaceElement? enclosingClassElement,
     ExecutableElement? enclosingExecutableElement,
   }) {
     enclosingClass = enclosingClassElement;
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 28b3ace..c50db2b 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -30,22 +30,6 @@
 /// rather than 'integerLiteral'.
 @internal
 class AstTestFactory {
-  static AnnotationImpl annotation(Identifier name) => astFactory.annotation(
-      atSign: TokenFactory.tokenFromType(TokenType.AT), name: name);
-
-  static AnnotationImpl annotation2(Identifier name,
-          SimpleIdentifier? constructorName, ArgumentList arguments,
-          {TypeArgumentList? typeArguments}) =>
-      astFactory.annotation(
-          atSign: TokenFactory.tokenFromType(TokenType.AT),
-          name: name,
-          typeArguments: typeArguments,
-          period: constructorName == null
-              ? null
-              : TokenFactory.tokenFromType(TokenType.PERIOD),
-          constructorName: constructorName,
-          arguments: arguments);
-
   static ArgumentListImpl argumentList(
           [List<Expression> arguments = const []]) =>
       ArgumentListImpl(
@@ -62,13 +46,6 @@
         rightHandSide: rightHandSide as ExpressionImpl,
       );
 
-  static BlockFunctionBodyImpl asyncBlockFunctionBody(
-          [List<Statement> statements = const []]) =>
-      astFactory.blockFunctionBody(
-          TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "async"),
-          null,
-          block(statements));
-
   static ExpressionFunctionBodyImpl asyncExpressionFunctionBody(
           Expression expression) =>
       astFactory.expressionFunctionBody2(
@@ -80,13 +57,6 @@
         semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
       );
 
-  static BlockFunctionBodyImpl asyncGeneratorBlockFunctionBody(
-          [List<Statement> statements = const []]) =>
-      astFactory.blockFunctionBody(
-          TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "async"),
-          TokenFactory.tokenFromType(TokenType.STAR),
-          block(statements));
-
   static ExpressionFunctionBodyImpl asyncGeneratorExpressionFunctionBody(
           Expression expression) =>
       astFactory.expressionFunctionBody2(
@@ -98,19 +68,6 @@
         semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
       );
 
-  static BlockImpl block([List<Statement> statements = const []]) =>
-      astFactory.block(
-          TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET),
-          statements,
-          TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET));
-
-  static BlockFunctionBodyImpl blockFunctionBody(Block block) =>
-      astFactory.blockFunctionBody(null, null, block);
-
-  static BlockFunctionBodyImpl blockFunctionBody2(
-          [List<Statement> statements = const []]) =>
-      astFactory.blockFunctionBody(null, null, block(statements));
-
   static BooleanLiteralImpl booleanLiteral(
           bool value) =>
       astFactory.booleanLiteral(
@@ -601,9 +558,6 @@
       astFactory.functionDeclarationStatement(
           functionDeclaration(type, keyword, name, functionExpression));
 
-  static FunctionExpressionImpl functionExpression() => astFactory
-      .functionExpression(null, formalParameterList(), blockFunctionBody2());
-
   static FunctionExpressionImpl functionExpression2(
           FormalParameterList parameters, FunctionBody body) =>
       astFactory.functionExpression(null, parameters, body);
@@ -1343,20 +1297,6 @@
         TokenFactory.tokenFromType(TokenType.HASH), identifierList);
   }
 
-  static BlockFunctionBodyImpl syncBlockFunctionBody(
-          [List<Statement> statements = const []]) =>
-      astFactory.blockFunctionBody(
-          TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "sync"),
-          null,
-          block(statements));
-
-  static BlockFunctionBodyImpl syncGeneratorBlockFunctionBody(
-          [List<Statement> statements = const []]) =>
-      astFactory.blockFunctionBody(
-          TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "sync"),
-          TokenFactory.tokenFromType(TokenType.STAR),
-          block(statements));
-
   static ThisExpressionImpl thisExpression() =>
       astFactory.thisExpression(TokenFactory.tokenFromKeyword(Keyword.THIS));
 
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index 9aa5440..a6937a0 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -199,11 +199,11 @@
   }
 
   Annotation _readAnnotation() {
-    var name = readNode() as Identifier;
-    var typeArguments = _readOptionalNode() as TypeArgumentList?;
-    var constructorName = _readOptionalNode() as SimpleIdentifier?;
-    var arguments = _readOptionalNode() as ArgumentList?;
-    var node = astFactory.annotation(
+    var name = readNode() as IdentifierImpl;
+    var typeArguments = _readOptionalNode() as TypeArgumentListImpl?;
+    var constructorName = _readOptionalNode() as SimpleIdentifierImpl?;
+    var arguments = _readOptionalNode() as ArgumentListImpl?;
+    var node = AnnotationImpl(
       atSign: Tokens.at(),
       name: name,
       typeArguments: typeArguments,
diff --git a/pkg/analyzer/lib/src/summary2/ast_resolver.dart b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
index e3976e43..a2a72d3 100644
--- a/pkg/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
@@ -23,7 +23,7 @@
   final FeatureSet _featureSet;
   final AnalysisErrorListener _errorListener =
       AnalysisErrorListener.NULL_LISTENER;
-  final ClassElement? enclosingClassElement;
+  final InterfaceElement? enclosingClassElement;
   final ExecutableElement? enclosingExecutableElement;
   late final _resolutionVisitor = ResolutionVisitor(
     unitElement: _unitElement,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 402d18c..70e39fc 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -796,7 +796,7 @@
     Reference unitReference,
   ) {
     var count = _reader.readUInt30();
-    unitElement.enums = List.generate(count, (_) {
+    unitElement.enums2 = List.generate(count, (_) {
       return _readEnumElement(unitElement, unitReference);
     });
   }
@@ -1141,7 +1141,7 @@
     Reference unitReference,
   ) {
     var length = _reader.readUInt30();
-    unitElement.mixins = List.generate(length, (index) {
+    unitElement.mixins2 = List.generate(length, (index) {
       return _readMixinElement(unitElement, unitReference);
     });
   }
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 833951d..b1a07e3 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -227,7 +227,7 @@
     }
   }
 
-  void _writeEnumElement(ClassElement element) {
+  void _writeEnumElement(EnumElement element) {
     element as EnumElementImpl;
     _sink.writeUInt30(_resolutionSink.offset);
     _sink._writeStringReference(element.name);
@@ -408,7 +408,7 @@
     });
   }
 
-  void _writeMixinElement(ClassElement element) {
+  void _writeMixinElement(MixinElement element) {
     element as MixinElementImpl;
     _sink.writeUInt30(_resolutionSink.offset);
 
@@ -545,10 +545,10 @@
     _sink._writeOptionalStringReference(unitElement.uri);
     _sink.writeBool(unitElement.isSynthetic);
     _writeList(unitElement.classes, _writeClassElement);
-    _writeList(unitElement.enums, _writeEnumElement);
+    _writeList(unitElement.enums2, _writeEnumElement);
     _writeList(unitElement.extensions, _writeExtensionElement);
     _writeList(unitElement.functions, _writeFunctionElement);
-    _writeList(unitElement.mixins, _writeMixinElement);
+    _writeList(unitElement.mixins2, _writeMixinElement);
     _writeList(unitElement.typeAliases, _writeTypeAliasElement);
 
     _writeList(
diff --git a/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart b/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart
index cafb22c..56dcd51 100644
--- a/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart
@@ -18,16 +18,16 @@
 
   void resolve() {
     for (var unitElement in _libraryElement.units) {
-      var classElements = [
+      var interfaceElements = [
         ...unitElement.classes,
-        ...unitElement.enums,
-        ...unitElement.mixins,
+        ...unitElement.enums2,
+        ...unitElement.mixins2,
       ];
-      for (var classElement in classElements) {
-        for (var constructorElement in classElement.constructors) {
+      for (var interfaceElement in interfaceElements) {
+        for (var constructorElement in interfaceElement.constructors) {
           _constructor(
             unitElement as CompilationUnitElementImpl,
-            classElement as AbstractClassElementImpl,
+            interfaceElement as AbstractClassElementImpl,
             constructorElement as ConstructorElementImpl,
           );
         }
diff --git a/pkg/analyzer/lib/src/summary2/default_value_resolver.dart b/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
index 8170e42..7e39cb4 100644
--- a/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
@@ -23,14 +23,14 @@
     for (var unitElement in _libraryElement.units.impl) {
       _UnitContext(unitElement)
         ..forEach(unitElement.classes, _class)
-        ..forEach(unitElement.enums, _class)
+        ..forEach(unitElement.enums2, _class)
         ..forEach(unitElement.extensions, _extension)
         ..forEach(unitElement.functions, _executable)
-        ..forEach(unitElement.mixins, _class);
+        ..forEach(unitElement.mixins2, _class);
     }
   }
 
-  void _class(_UnitContext context, ClassElement element) {
+  void _class(_UnitContext context, InterfaceElement element) {
     _ClassContext(context, element)
       ..forEach(element.constructors, _constructor)
       ..forEach(element.methods, _executable);
@@ -92,7 +92,7 @@
   final _UnitContext unitContext;
 
   @override
-  final ClassElement classElement;
+  final InterfaceElement classElement;
 
   _ClassContext(this.unitContext, this.classElement);
 
@@ -103,7 +103,7 @@
 }
 
 abstract class _Context {
-  ClassElement? get classElement => null;
+  InterfaceElement? get classElement => null;
 
   CompilationUnitElementImpl get unitElement;
 }
@@ -120,7 +120,9 @@
   });
 
   @override
-  ClassElement? get classElement => enclosingContext.classElement;
+  InterfaceElement? get classElement {
+    return enclosingContext.classElement;
+  }
 
   @override
   CompilationUnitElementImpl get unitElement {
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 446b4d1..a9bb9a2 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -49,10 +49,10 @@
     _visitPropertyFirst<TopLevelVariableDeclaration>(unit.declarations);
     _unitElement.accessors = _enclosingContext.propertyAccessors;
     _unitElement.classes = _enclosingContext.classes;
-    _unitElement.enums = _enclosingContext.enums;
+    _unitElement.enums2 = _enclosingContext.enums;
     _unitElement.extensions = _enclosingContext.extensions;
     _unitElement.functions = _enclosingContext.functions;
-    _unitElement.mixins = _enclosingContext.mixins;
+    _unitElement.mixins2 = _enclosingContext.mixins;
     _unitElement.topLevelVariables = _enclosingContext.properties
         .whereType<TopLevelVariableElementImpl>()
         .toList();
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 482012f..3b1d277 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -109,7 +109,7 @@
         );
 
         forCorrespondingPairs(
-            unitElement.enums, unitInfo.enums, _applyToEnumDeclaration);
+            unitElement.enums2, unitInfo.enums, _applyToEnumDeclaration);
 
         forCorrespondingPairs(unitElement.extensions, unitInfo.extensions,
             _applyToExtensionDeclaration);
@@ -117,7 +117,7 @@
         forCorrespondingPairs(unitElement.functions, unitInfo.functions,
             _applyToFunctionDeclaration);
 
-        forCorrespondingPairs(unitElement.mixins, unitInfo.mixinDeclarations,
+        forCorrespondingPairs(unitElement.mixins2, unitInfo.mixinDeclarations,
             _applyToMixinDeclaration);
 
         forCorrespondingPairs(unitElement.topLevelVariables,
@@ -306,7 +306,7 @@
   }
 
   void _applyToEnumDeclaration(
-    ClassElement element,
+    EnumElement element,
     _InfoClassDeclaration info,
   ) {
     element as EnumElementImpl;
@@ -573,7 +573,7 @@
   }
 
   void _applyToMixinDeclaration(
-    ClassElement element,
+    MixinElement element,
     _InfoClassDeclaration info,
   ) {
     element as MixinElementImpl;
diff --git a/pkg/analyzer/lib/src/summary2/not_serializable_nodes.dart b/pkg/analyzer/lib/src/summary2/not_serializable_nodes.dart
index 95e3adf..4c20261 100644
--- a/pkg/analyzer/lib/src/summary2/not_serializable_nodes.dart
+++ b/pkg/analyzer/lib/src/summary2/not_serializable_nodes.dart
@@ -19,13 +19,13 @@
       null,
       Tokens.closeParenthesis(),
     ),
-    astFactory.blockFunctionBody(
-      null,
-      null,
-      astFactory.block(
-        Tokens.openCurlyBracket(),
-        [],
-        Tokens.closeCurlyBracket(),
+    BlockFunctionBodyImpl(
+      keyword: null,
+      star: null,
+      block: BlockImpl(
+        leftBracket: Tokens.openCurlyBracket(),
+        statements: [],
+        rightBracket: Tokens.closeCurlyBracket(),
       ),
     ),
   );
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index 660df6f..19ac2d7 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -21,11 +21,11 @@
         var node = walker.getNode(element);
         nodes.add(node);
       }
-      for (var element in unit.enums) {
+      for (var element in unit.enums2) {
         var node = walker.getNode(element);
         nodes.add(node);
       }
-      for (var element in unit.mixins) {
+      for (var element in unit.mixins2) {
         var node = walker.getNode(element);
         nodes.add(node);
       }
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 1b096ae..a5a5f13 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -42,10 +42,10 @@
       _library = builder.element;
       for (var unit in _library.units) {
         _unitElement = unit as CompilationUnitElementImpl;
-        unit.classes.forEach(_resolveClassFields);
-        unit.enums.forEach(_resolveClassFields);
+        unit.classes.forEach(_resolveInterfaceFields);
+        unit.enums2.forEach(_resolveInterfaceFields);
         unit.extensions.forEach(_resolveExtensionFields);
-        unit.mixins.forEach(_resolveClassFields);
+        unit.mixins2.forEach(_resolveInterfaceFields);
 
         _scope = unit.enclosingElement3.scope;
         unit.topLevelVariables.forEach(_resolveVariable);
@@ -53,7 +53,15 @@
     }
   }
 
-  void _resolveClassFields(ClassElement class_) {
+  void _resolveExtensionFields(ExtensionElement extension_) {
+    var node = linker.getLinkingNode(extension_)!;
+    _scope = LinkingNodeContext.get(node).scope;
+    for (var element in extension_.fields) {
+      _resolveVariable(element);
+    }
+  }
+
+  void _resolveInterfaceFields(InterfaceElement class_) {
     _enclosingClassHasConstConstructor =
         class_.constructors.any((c) => c.isConst);
 
@@ -65,14 +73,6 @@
     _enclosingClassHasConstConstructor = false;
   }
 
-  void _resolveExtensionFields(ExtensionElement extension_) {
-    var node = linker.getLinkingNode(extension_)!;
-    _scope = LinkingNodeContext.get(node).scope;
-    for (var element in extension_.fields) {
-      _resolveVariable(element);
-    }
-  }
-
   void _resolveVariable(PropertyInducingElement element) {
     element as PropertyInducingElementImpl;
 
@@ -351,10 +351,10 @@
         _unitElement = unit as CompilationUnitElementImpl;
         unit.classes.forEach(_addClassConstructorFieldFormals);
         unit.classes.forEach(_addClassElementFields);
-        unit.enums.forEach(_addClassConstructorFieldFormals);
-        unit.enums.forEach(_addClassElementFields);
+        unit.enums2.forEach(_addClassConstructorFieldFormals);
+        unit.enums2.forEach(_addClassElementFields);
         unit.extensions.forEach(_addExtensionElementFields);
-        unit.mixins.forEach(_addClassElementFields);
+        unit.mixins2.forEach(_addClassElementFields);
 
         _scope = unit.enclosingElement3.scope;
         for (var element in unit.topLevelVariables) {
@@ -368,7 +368,7 @@
     _walker.walkNodes();
   }
 
-  void _addClassConstructorFieldFormals(ClassElement class_) {
+  void _addClassConstructorFieldFormals(InterfaceElement class_) {
     for (var constructor in class_.constructors) {
       constructor as ConstructorElementImpl;
       var inferenceNode = _ConstructorInferenceNode(_walker, constructor);
@@ -376,7 +376,7 @@
     }
   }
 
-  void _addClassElementFields(ClassElement class_) {
+  void _addClassElementFields(InterfaceElement class_) {
     var node = _linker.getLinkingNode(class_)!;
     _scope = LinkingNodeContext.get(node).scope;
     for (var element in class_.fields) {
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index d0b5ca2..ee331d8 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -35,7 +35,7 @@
     typeSystem = unit.library.typeSystem as TypeSystemImpl;
     isNonNullableByDefault = typeSystem.isNonNullableByDefault;
     _inferClasses(unit.classes);
-    _inferClasses(unit.mixins);
+    _inferClasses(unit.mixins2);
   }
 
   /// Return `true` if the elements corresponding to the [elements] have the
@@ -308,7 +308,7 @@
 
   /// Infer type information for all of the instance members in the given
   /// [classElement].
-  void _inferClass(ClassElement classElement) {
+  void _inferClass(InterfaceElement classElement) {
     if (classElement is ClassElementImpl) {
       if (classElement.hasBeenInferred) {
         return;
@@ -359,8 +359,8 @@
     }
   }
 
-  void _inferClasses(List<ClassElement> elements) {
-    for (ClassElement element in elements) {
+  void _inferClasses(List<InterfaceElement> elements) {
+    for (final element in elements) {
       try {
         _inferClass(element);
       } on _CycleException {
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index 31801f0..aa8aef9 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -171,7 +171,7 @@
       }
     }
 
-    void findInClasses(List<ClassElement> classes) {
+    void findInClasses(List<InterfaceElement> classes) {
       for (var class_ in classes) {
         findInExecutables(class_.accessors);
         findInExecutables(class_.constructors);
@@ -183,8 +183,8 @@
     findInExecutables(unitElement.functions);
 
     findInClasses(unitElement.classes);
-    findInClasses(unitElement.enums);
-    findInClasses(unitElement.mixins);
+    findInClasses(unitElement.enums2);
+    findInClasses(unitElement.mixins2);
 
     for (var extension_ in unitElement.extensions) {
       findInExecutables(extension_.accessors);
@@ -264,7 +264,7 @@
       }
     }
 
-    void findInClass(ClassElement class_) {
+    void findInClass(InterfaceElement class_) {
       findIn(class_.typeParameters);
       for (var method in class_.methods) {
         findIn(method.typeParameters);
@@ -288,7 +288,7 @@
       findInClass(class_);
     }
 
-    for (var enum_ in unitElement.enums) {
+    for (var enum_ in unitElement.enums2) {
       findInClass(enum_);
     }
 
@@ -296,7 +296,7 @@
       findIn(extension_.typeParameters);
     }
 
-    for (var mixin in unitElement.mixins) {
+    for (var mixin in unitElement.mixins2) {
       findInClass(mixin);
     }
 
@@ -342,13 +342,13 @@
     throw StateError('Not found: $name');
   }
 
-  ClassElement classOrMixin(String name) {
+  InterfaceElement classOrMixin(String name) {
     for (var class_ in unitElement.classes) {
       if (class_.name == name) {
         return class_;
       }
     }
-    for (var mixin in unitElement.mixins) {
+    for (var mixin in unitElement.mixins2) {
       if (mixin.name == name) {
         return mixin;
       }
@@ -378,7 +378,7 @@
       }
     }
 
-    for (var enum_ in unitElement.enums) {
+    for (var enum_ in unitElement.enums2) {
       if (of == null || enum_.name == of) {
         findIn(enum_.constructors);
       }
@@ -390,8 +390,8 @@
     throw StateError('Not found: $name');
   }
 
-  ClassElement enum_(String name) {
-    for (var enum_ in unitElement.enums) {
+  EnumElement enum_(String name) {
+    for (var enum_ in unitElement.enums2) {
       if (enum_.name == name) {
         return enum_;
       }
@@ -432,8 +432,8 @@
     );
   }
 
-  ClassElement mixin(String name) {
-    for (var mixin in unitElement.mixins) {
+  MixinElement mixin(String name) {
+    for (var mixin in unitElement.mixins2) {
       if (mixin.name == name) {
         return mixin;
       }
@@ -516,7 +516,7 @@
 
   T _findInClassesLike<T extends Element>({
     required String? className,
-    required T? Function(ClassElement element) fromClass,
+    required T? Function(InterfaceElement element) fromClass,
     required T? Function(ExtensionElement element) fromExtension,
   }) {
     bool filter(Element element) {
@@ -525,8 +525,8 @@
 
     var classes = [
       ...unitElement.classes,
-      ...unitElement.enums,
-      ...unitElement.mixins,
+      ...unitElement.enums2,
+      ...unitElement.mixins2,
     ];
 
     var results = [
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index ef1da68..b4e5a11 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -21251,11 +21251,19 @@
       The analyzer produces this diagnostic when a private declaration isn't
       referenced in the library that contains the declaration. The following
       kinds of declarations are analyzed:
-      - Private top-level declarations, such as classes, enums, mixins, typedefs,
-        top-level variables, and top-level functions
-      - Private static and instance methods
+      - Private top-level declarations and all of their members
+      - Private members of public declarations
       - Optional parameters of private functions for which a value is never
-        passed, even when the parameter doesn't have a private name
+        passed
+
+      Not all references to an element will mark it as "used":
+      - Assigning a value to a top-level variable (with a standard `=`
+        assignment, or a null-aware `??=` assignment) does not count as using
+        it.
+      - Refering to an element in a doc comment reference does not count as
+        using it.
+      - Refering to a class, mixin, or enum in the right side of an `is`
+        expression does not count as using it.
 
       #### Example
 
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index a569500..3e6441a 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
+import 'package:analyzer/src/summary2/ast_binary_tokens.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -1504,7 +1505,11 @@
   void test_inGetterContext_forEachLoop() {
     SimpleIdentifier identifier = AstTestFactory.identifier3("a");
     Expression iterator = AstTestFactory.listLiteral();
-    Statement body = AstTestFactory.block();
+    Statement body = BlockImpl(
+      leftBracket: Tokens.openCurlyBracket(),
+      statements: [],
+      rightBracket: Tokens.closeCurlyBracket(),
+    );
     AstTestFactory.forStatement(
         AstTestFactory.forEachPartsWithIdentifier(identifier, iterator), body);
     expect(identifier.inGetterContext(), isFalse);
@@ -1544,7 +1549,11 @@
   void test_inSetterContext_forEachLoop() {
     SimpleIdentifier identifier = AstTestFactory.identifier3("a");
     Expression iterator = AstTestFactory.listLiteral();
-    Statement body = AstTestFactory.block();
+    Statement body = BlockImpl(
+      leftBracket: Tokens.openCurlyBracket(),
+      statements: [],
+      rightBracket: Tokens.closeCurlyBracket(),
+    );
     AstTestFactory.forStatement(
         AstTestFactory.forEachPartsWithIdentifier(identifier, iterator), body);
     expect(identifier.inSetterContext(), isTrue);
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index b3245ba..dcb1633 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -526,7 +526,7 @@
 mixin A {} // 1
 class B extends Object with A {} // 2
 ''');
-    ClassElement elementA = findElement.mixin('A');
+    final elementA = findElement.mixin('A');
     assertThat(elementA)
       ..isMixedInAt('A {} // 2', false)
       ..isReferencedAt('A {} // 2', false);
@@ -546,7 +546,7 @@
 mixin A {} // 1
 class B = Object with A; // 2
 ''');
-    ClassElement elementA = findElement.mixin('A');
+    final elementA = findElement.mixin('A');
     assertThat(elementA).isMixedInAt('A; // 2', false);
   }
 
@@ -622,7 +622,7 @@
   MyEnum.a;
 }
 ''');
-    ClassElement element = findElement.enum_('MyEnum');
+    final element = findElement.enum_('MyEnum');
     assertThat(element)
       ..isReferencedAt('MyEnum p) {', false)
       ..isReferencedAt('MyEnum v;', false)
@@ -1169,7 +1169,7 @@
   print(MyEnum.B);
 }
 ''');
-    ClassElement enumElement = findElement.enum_('MyEnum');
+    final enumElement = findElement.enum_('MyEnum');
     assertThat(enumElement.getGetter('values')!)
         .isReferencedAt('values);', true);
     assertThat(typeProvider.enumElement!.getGetter('index')!)
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index ccfc496..9ed16ce 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -35,24 +35,30 @@
   }
 
   void test_visitAnnotation_constant() {
-    _assertSource(
-        "@A", AstTestFactory.annotation(AstTestFactory.identifier3("A")));
+    final code = '@A';
+    final findNode = _parseStringToFindNode('''
+$code
+void f() {}
+''');
+    _assertSource(code, findNode.annotation(code));
   }
 
   void test_visitAnnotation_constructor() {
-    _assertSource(
-        "@A.c()",
-        AstTestFactory.annotation2(AstTestFactory.identifier3("A"),
-            AstTestFactory.identifier3("c"), AstTestFactory.argumentList()));
+    final code = '@A.foo()';
+    final findNode = _parseStringToFindNode('''
+$code
+void f() {}
+''');
+    _assertSource(code, findNode.annotation(code));
   }
 
   void test_visitAnnotation_constructor_generic() {
-    _assertSource(
-        "@A<T>.c()",
-        AstTestFactory.annotation2(AstTestFactory.identifier3("A"),
-            AstTestFactory.identifier3("c"), AstTestFactory.argumentList(),
-            typeArguments: AstTestFactory.typeArgumentList2(
-                [AstTestFactory.namedType4('T')])));
+    final code = '@A<int>.foo()';
+    final findNode = _parseStringToFindNode('''
+$code
+void f() {}
+''');
+    _assertSource(code, findNode.annotation(code));
   }
 
   void test_visitArgumentList() {
@@ -146,37 +152,51 @@
   }
 
   void test_visitBlock_empty() {
-    _assertSource("{}", AstTestFactory.block());
+    final code = '{}';
+    final findNode = _parseStringToFindNode('''
+void f() $code
+''');
+    _assertSource(code, findNode.block(code));
   }
 
   void test_visitBlock_nonEmpty() {
-    _assertSource(
-        "{break; break;}",
-        AstTestFactory.block([
-          AstTestFactory.breakStatement(),
-          AstTestFactory.breakStatement()
-        ]));
+    final code = '{foo(); bar();}';
+    final findNode = _parseStringToFindNode('''
+void f() $code
+''');
+    _assertSource(code, findNode.block(code));
   }
 
   void test_visitBlockFunctionBody_async() {
-    _assertSource("async {}", AstTestFactory.asyncBlockFunctionBody());
+    final code = 'async {}';
+    final findNode = _parseStringToFindNode('''
+void f() $code
+''');
+    _assertSource(code, findNode.blockFunctionBody(code));
   }
 
   void test_visitBlockFunctionBody_async_star() {
-    _assertSource(
-        "async* {}", AstTestFactory.asyncGeneratorBlockFunctionBody());
+    final code = 'async* {}';
+    final findNode = _parseStringToFindNode('''
+void f() $code
+''');
+    _assertSource(code, findNode.blockFunctionBody(code));
   }
 
   void test_visitBlockFunctionBody_simple() {
-    _assertSource("{}", AstTestFactory.blockFunctionBody2());
-  }
-
-  void test_visitBlockFunctionBody_sync() {
-    _assertSource("sync {}", AstTestFactory.syncBlockFunctionBody());
+    final code = '{}';
+    final findNode = _parseStringToFindNode('''
+void f() $code
+''');
+    _assertSource(code, findNode.blockFunctionBody(code));
   }
 
   void test_visitBlockFunctionBody_sync_star() {
-    _assertSource("sync* {}", AstTestFactory.syncGeneratorBlockFunctionBody());
+    final code = 'sync* {}';
+    final findNode = _parseStringToFindNode('''
+void f() $code
+''');
+    _assertSource(code, findNode.blockFunctionBody(code));
   }
 
   void test_visitBooleanLiteral_false() {
@@ -457,11 +477,9 @@
   }
 
   void test_visitClassDeclaration_withMetadata() {
-    ClassDeclaration declaration =
-        AstTestFactory.classDeclaration(null, "C", null, null, null, null);
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated class C {}", declaration);
+    final code = '@deprecated class C {}';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.classDeclaration(code));
   }
 
   void test_visitClassTypeAlias_abstract() {
@@ -609,16 +627,9 @@
   }
 
   void test_visitClassTypeAlias_withMetadata() {
-    ClassTypeAlias declaration = AstTestFactory.classTypeAlias(
-        "C",
-        null,
-        null,
-        AstTestFactory.namedType4("S"),
-        AstTestFactory.withClause([AstTestFactory.namedType4("M1")]),
-        null);
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated class C = S with M1;", declaration);
+    final code = '@deprecated class A = S with M;';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.classTypeAlias(code));
   }
 
   void test_visitComment() {
@@ -704,16 +715,13 @@
   }
 
   void test_visitConstructorDeclaration_const() {
-    _assertSource(
-        "const C() {}",
-        AstTestFactory.constructorDeclaration2(
-            Keyword.CONST,
-            null,
-            AstTestFactory.identifier3("C"),
-            null,
-            AstTestFactory.formalParameterList(),
-            [],
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'const A();';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorDeclaration_external() {
@@ -724,93 +732,63 @@
   }
 
   void test_visitConstructorDeclaration_minimal() {
-    _assertSource(
-        "C() {}",
-        AstTestFactory.constructorDeclaration2(
-            null,
-            null,
-            AstTestFactory.identifier3("C"),
-            null,
-            AstTestFactory.formalParameterList(),
-            [],
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'A();';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorDeclaration_multipleInitializers() {
-    _assertSource(
-        "C() : a = b, c = d {}",
-        AstTestFactory.constructorDeclaration2(
-            null,
-            null,
-            AstTestFactory.identifier3("C"),
-            null,
-            AstTestFactory.formalParameterList(),
-            [
-              AstTestFactory.constructorFieldInitializer(
-                  false, "a", AstTestFactory.identifier3("b")),
-              AstTestFactory.constructorFieldInitializer(
-                  false, "c", AstTestFactory.identifier3("d"))
-            ],
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'A() : a = b, c = d {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorDeclaration_multipleParameters() {
-    _assertSource(
-        "C(var a, var b) {}",
-        AstTestFactory.constructorDeclaration2(
-            null,
-            null,
-            AstTestFactory.identifier3("C"),
-            null,
-            AstTestFactory.formalParameterList([
-              AstTestFactory.simpleFormalParameter(Keyword.VAR, "a"),
-              AstTestFactory.simpleFormalParameter(Keyword.VAR, "b")
-            ]),
-            [],
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'A(int a, double b);';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorDeclaration_named() {
-    _assertSource(
-        "C.m() {}",
-        AstTestFactory.constructorDeclaration2(
-            null,
-            null,
-            AstTestFactory.identifier3("C"),
-            "m",
-            AstTestFactory.formalParameterList(),
-            [],
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'A.foo();';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorDeclaration_singleInitializer() {
-    _assertSource(
-        "C() : a = b {}",
-        AstTestFactory.constructorDeclaration2(
-            null,
-            null,
-            AstTestFactory.identifier3("C"),
-            null,
-            AstTestFactory.formalParameterList(),
-            [
-              AstTestFactory.constructorFieldInitializer(
-                  false, "a", AstTestFactory.identifier3("b"))
-            ],
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'A() : a = b;';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorDeclaration_withMetadata() {
-    ConstructorDeclaration declaration = AstTestFactory.constructorDeclaration2(
-        null,
-        null,
-        AstTestFactory.identifier3("C"),
-        null,
-        AstTestFactory.formalParameterList(),
-        [],
-        AstTestFactory.blockFunctionBody2());
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated C() {}", declaration);
+    final code = '@deprecated C() {}';
+    final findNode = _parseStringToFindNode('''
+class C {
+  $code
+}
+''');
+    _assertSource(code, findNode.constructor(code));
   }
 
   void test_visitConstructorFieldInitializer_withoutThis() {
@@ -856,11 +834,11 @@
   }
 
   void test_visitDefaultFormalParameter_annotation() {
-    DefaultFormalParameter parameter = AstTestFactory.positionalFormalParameter(
-        AstTestFactory.simpleFormalParameter3("p"), AstTestFactory.integer(0));
-    parameter.metadata
-        .add(AstTestFactory.annotation(AstTestFactory.identifier3("A")));
-    _assertSource('@A p = 0', parameter);
+    final code = '@deprecated p = 0';
+    final findNode = _parseStringToFindNode('''
+void f([$code]) {}
+''');
+    _assertSource(code, findNode.defaultParameter(code));
   }
 
   void test_visitDefaultFormalParameter_named_noValue() {
@@ -894,10 +872,13 @@
   }
 
   void test_visitDoStatement() {
-    _assertSource(
-        "do {} while (c);",
-        AstTestFactory.doStatement(
-            AstTestFactory.block(), AstTestFactory.identifier3("c")));
+    final code = 'do {} while (true);';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.doStatement(code));
   }
 
   void test_visitDoubleLiteral() {
@@ -1032,10 +1013,9 @@
   }
 
   void test_visitExportDirective_withMetadata() {
-    ExportDirective directive = AstTestFactory.exportDirective2("a.dart");
-    directive.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated export 'a.dart';", directive);
+    final code = '@deprecated export "a.dart";';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.export(code));
   }
 
   void test_visitExpressionFunctionBody_async() {
@@ -1427,18 +1407,24 @@
   }
 
   void test_visitFieldDeclaration_withMetadata() {
-    FieldDeclaration declaration = AstTestFactory.fieldDeclaration2(
-        false, Keyword.VAR, [AstTestFactory.variableDeclaration("a")]);
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated var a;", declaration);
+    final code = '@deprecated var a;';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.fieldDeclaration(code));
   }
 
   void test_visitFieldFormalParameter_annotation() {
-    FieldFormalParameter parameter = AstTestFactory.fieldFormalParameter2('f');
-    parameter.metadata
-        .add(AstTestFactory.annotation(AstTestFactory.identifier3("A")));
-    _assertSource('@A this.f', parameter);
+    final code = '@deprecated this.foo';
+    final findNode = _parseStringToFindNode('''
+class A {
+  final int foo;
+  A($code);
+}
+''');
+    _assertSource(code, findNode.fieldFormalParameter(code));
   }
 
   void test_visitFieldFormalParameter_functionTyped() {
@@ -1511,42 +1497,33 @@
   }
 
   void test_visitForEachStatement_declared() {
-    _assertSource(
-        "for (var a in b) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forEachPartsWithDeclaration(
-                AstTestFactory.declaredIdentifier3("a"),
-                AstTestFactory.identifier3("b")),
-            AstTestFactory.block()));
+    final code = 'for (final a in b) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForEachStatement_variable() {
-    _assertSource(
-        "for (a in b) {}",
-        astFactory.forStatement(
-            forKeyword: TokenFactory.tokenFromKeyword(Keyword.FOR),
-            leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-            forLoopParts: astFactory.forEachPartsWithIdentifier(
-                identifier: AstTestFactory.identifier3("a"),
-                inKeyword: TokenFactory.tokenFromKeyword(Keyword.IN),
-                iterable: AstTestFactory.identifier3("b")),
-            rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-            body: AstTestFactory.block()));
+    final code = 'for (a in b) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForEachStatement_variable_await() {
-    _assertSource(
-        "await for (a in b) {}",
-        astFactory.forStatement(
-            awaitKeyword: TokenFactory.tokenFromString("await"),
-            forKeyword: TokenFactory.tokenFromKeyword(Keyword.FOR),
-            leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-            forLoopParts: astFactory.forEachPartsWithIdentifier(
-                identifier: AstTestFactory.identifier3("a"),
-                inKeyword: TokenFactory.tokenFromKeyword(Keyword.IN),
-                iterable: AstTestFactory.identifier3("b")),
-            rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-            body: AstTestFactory.block()));
+    final code = 'await for (final a in b) {}';
+    final findNode = _parseStringToFindNode('''
+void f() async {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForElement() {
@@ -1792,122 +1769,113 @@
   }
 
   void test_visitForStatement_c() {
-    _assertSource(
-        "for (; c;) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                null, AstTestFactory.identifier3("c"), null),
-            AstTestFactory.block()));
+    final code = 'for (; c;) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_cu() {
-    _assertSource(
-        "for (; c; u) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                null,
-                AstTestFactory.identifier3("c"),
-                [AstTestFactory.identifier3("u")]),
-            AstTestFactory.block()));
+    final code = 'for (; c; u) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_e() {
-    _assertSource(
-        "for (e;;) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                AstTestFactory.identifier3("e"), null, null),
-            AstTestFactory.block()));
+    final code = 'for (e;;) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_ec() {
-    _assertSource(
-        "for (e; c;) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                AstTestFactory.identifier3("e"),
-                AstTestFactory.identifier3("c"),
-                null),
-            AstTestFactory.block()));
+    final code = 'for (e; c;) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_ecu() {
-    _assertSource(
-        "for (e; c; u) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                AstTestFactory.identifier3("e"),
-                AstTestFactory.identifier3("c"),
-                [AstTestFactory.identifier3("u")]),
-            AstTestFactory.block()));
+    final code = 'for (e; c; u) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_eu() {
-    _assertSource(
-        "for (e;; u) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                AstTestFactory.identifier3("e"),
-                null,
-                [AstTestFactory.identifier3("u")]),
-            AstTestFactory.block()));
+    final code = 'for (e;; u) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_i() {
-    _assertSource(
-        "for (var i;;) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithDeclarations(
-                AstTestFactory.variableDeclarationList2(
-                    Keyword.VAR, [AstTestFactory.variableDeclaration("i")]),
-                null,
-                null),
-            AstTestFactory.block()));
+    final code = 'for (var i;;) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_ic() {
-    _assertSource(
-        "for (var i; c;) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithDeclarations(
-                AstTestFactory.variableDeclarationList2(
-                    Keyword.VAR, [AstTestFactory.variableDeclaration("i")]),
-                AstTestFactory.identifier3("c"),
-                null),
-            AstTestFactory.block()));
+    final code = 'for (var i; c;) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_icu() {
-    _assertSource(
-        "for (var i; c; u) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithDeclarations(
-                AstTestFactory.variableDeclarationList2(
-                    Keyword.VAR, [AstTestFactory.variableDeclaration("i")]),
-                AstTestFactory.identifier3("c"),
-                [AstTestFactory.identifier3("u")]),
-            AstTestFactory.block()));
+    final code = 'for (var i; c; u) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_iu() {
-    _assertSource(
-        "for (var i;; u) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithDeclarations(
-                AstTestFactory.variableDeclarationList2(
-                    Keyword.VAR, [AstTestFactory.variableDeclaration("i")]),
-                null,
-                [AstTestFactory.identifier3("u")]),
-            AstTestFactory.block()));
+    final code = 'for (var i;; u) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitForStatement_u() {
-    _assertSource(
-        "for (;; u) {}",
-        AstTestFactory.forStatement(
-            AstTestFactory.forPartsWithExpression(
-                null, null, [AstTestFactory.identifier3("u")]),
-            AstTestFactory.block()));
+    final code = 'for (;; u) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.forStatement(code));
   }
 
   void test_visitFunctionDeclaration_external() {
@@ -1923,107 +1891,79 @@
   }
 
   void test_visitFunctionDeclaration_getter() {
-    _assertSource(
-        "get f() {}",
-        AstTestFactory.functionDeclaration(
-            null, Keyword.GET, "f", AstTestFactory.functionExpression()));
+    final code = 'get foo {}';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclaration_local_blockBody() {
-    FunctionDeclaration f = AstTestFactory.functionDeclaration(
-        null, null, "f", AstTestFactory.functionExpression());
-    FunctionDeclarationStatement fStatement =
-        astFactory.functionDeclarationStatement(f);
-    _assertSource(
-        "main() {f() {} 42;}",
-        AstTestFactory.functionDeclaration(
-            null,
-            null,
-            "main",
-            AstTestFactory.functionExpression2(
-                AstTestFactory.formalParameterList(),
-                AstTestFactory.blockFunctionBody2([
-                  fStatement,
-                  AstTestFactory.expressionStatement(AstTestFactory.integer(42))
-                ]))));
+    final code = 'void foo() {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  $code
+}
+''');
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclaration_local_expressionBody() {
-    FunctionDeclaration f = AstTestFactory.functionDeclaration(
-        null,
-        null,
-        "f",
-        AstTestFactory.functionExpression2(AstTestFactory.formalParameterList(),
-            AstTestFactory.expressionFunctionBody(AstTestFactory.integer(1))));
-    FunctionDeclarationStatement fStatement =
-        astFactory.functionDeclarationStatement(f);
-    _assertSource(
-        "main() {f() => 1; 2;}",
-        AstTestFactory.functionDeclaration(
-            null,
-            null,
-            "main",
-            AstTestFactory.functionExpression2(
-                AstTestFactory.formalParameterList(),
-                AstTestFactory.blockFunctionBody2([
-                  fStatement,
-                  AstTestFactory.expressionStatement(AstTestFactory.integer(2))
-                ]))));
+    final code = 'int foo() => 42;';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  $code
+}
+''');
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclaration_normal() {
-    _assertSource(
-        "f() {}",
-        AstTestFactory.functionDeclaration(
-            null, null, "f", AstTestFactory.functionExpression()));
+    final code = 'void foo() {}';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclaration_setter() {
-    _assertSource(
-        "set f() {}",
-        AstTestFactory.functionDeclaration(
-            null, Keyword.SET, "f", AstTestFactory.functionExpression()));
+    final code = 'set foo(int _) {}';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclaration_typeParameters() {
-    _assertSource(
-        "f<E>() {}",
-        AstTestFactory.functionDeclaration(
-            null,
-            null,
-            "f",
-            AstTestFactory.functionExpression3(
-                AstTestFactory.typeParameterList2(['E']),
-                AstTestFactory.formalParameterList(),
-                AstTestFactory.blockFunctionBody2())));
+    final code = 'void foo<T>() {}';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclaration_withMetadata() {
-    FunctionDeclaration declaration = AstTestFactory.functionDeclaration(
-        null, null, "f", AstTestFactory.functionExpression());
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated f() {}", declaration);
+    final code = '@deprecated void f() {}';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionDeclarationStatement() {
-    _assertSource(
-        "f() {}",
-        AstTestFactory.functionDeclarationStatement(
-            null, null, "f", AstTestFactory.functionExpression()));
+    final code = 'void foo() {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  $code
+}
+''');
+    _assertSource(code, findNode.functionDeclaration(code));
   }
 
   void test_visitFunctionExpression() {
-    _assertSource("() {}", AstTestFactory.functionExpression());
+    final code = '() {}';
+    final findNode = _parseStringToFindNode('''
+final f = $code;
+''');
+    _assertSource(code, findNode.functionExpression(code));
   }
 
   void test_visitFunctionExpression_typeParameters() {
-    _assertSource(
-        "<E>() {}",
-        AstTestFactory.functionExpression3(
-            AstTestFactory.typeParameterList2(['E']),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = '<T>() {}';
+    final findNode = _parseStringToFindNode('''
+final f = $code;
+''');
+    _assertSource(code, findNode.functionExpression(code));
   }
 
   void test_visitFunctionExpressionInvocation_minimal() {
@@ -2059,22 +1999,17 @@
   }
 
   void test_visitFunctionTypeAlias_withMetadata() {
-    FunctionTypeAlias declaration = AstTestFactory.typeAlias(
-        AstTestFactory.namedType4("A"),
-        "F",
-        null,
-        AstTestFactory.formalParameterList());
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated typedef A F();", declaration);
+    final code = '@deprecated typedef void F();';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.functionTypeAlias(code));
   }
 
   void test_visitFunctionTypedFormalParameter_annotation() {
-    FunctionTypedFormalParameter parameter =
-        AstTestFactory.functionTypedFormalParameter(null, "f");
-    parameter.metadata
-        .add(AstTestFactory.annotation(AstTestFactory.identifier3("A")));
-    _assertSource('@A f()', parameter);
+    final code = '@deprecated g()';
+    final findNode = _parseStringToFindNode('''
+void f($code) {}
+''');
+    _assertSource(code, findNode.functionTypedFormalParameter(code));
   }
 
   void test_visitFunctionTypedFormalParameter_noType() {
@@ -2182,17 +2117,23 @@
   }
 
   void test_visitIfStatement_withElse() {
-    _assertSource(
-        "if (c) {} else {}",
-        AstTestFactory.ifStatement2(AstTestFactory.identifier3("c"),
-            AstTestFactory.block(), AstTestFactory.block()));
+    final code = 'if (c) {} else {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.ifStatement(code));
   }
 
   void test_visitIfStatement_withoutElse() {
-    _assertSource(
-        "if (c) {}",
-        AstTestFactory.ifStatement(
-            AstTestFactory.identifier3("c"), AstTestFactory.block()));
+    final code = 'if (c) {}';
+    final findNode = _parseStringToFindNode('''
+void f () {
+  $code
+}
+''');
+    _assertSource(code, findNode.ifStatement(code));
   }
 
   void test_visitImplementsClause_multiple() {
@@ -2272,10 +2213,9 @@
   }
 
   void test_visitImportDirective_withMetadata() {
-    ImportDirective directive = AstTestFactory.importDirective3("a.dart", null);
-    directive.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated import 'a.dart';", directive);
+    final code = '@deprecated import "a.dart";';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.import(code));
   }
 
   void test_visitImportHideCombinator_multiple() {
@@ -2404,10 +2344,9 @@
   }
 
   void test_visitLibraryDirective_withMetadata() {
-    LibraryDirective directive = AstTestFactory.libraryDirective2("l");
-    directive.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated library l;", directive);
+    final code = '@deprecated library my;';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.library(code));
   }
 
   void test_visitLibraryIdentifier_multiple() {
@@ -2569,179 +2508,133 @@
   }
 
   void test_visitMethodDeclaration_getter() {
-    _assertSource(
-        "get m {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            null,
-            Keyword.GET,
-            null,
-            AstTestFactory.identifier3("m"),
-            null,
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'get foo => 0;';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_getter_returnType() {
-    _assertSource(
-        "T get m {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            AstTestFactory.namedType4("T"),
-            Keyword.GET,
-            null,
-            AstTestFactory.identifier3("m"),
-            null,
-            AstTestFactory.blockFunctionBody2()));
-  }
-
-  void test_visitMethodDeclaration_getter_seturnType() {
-    _assertSource(
-        "T set m(var v) {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            AstTestFactory.namedType4("T"),
-            Keyword.SET,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList(
-                [AstTestFactory.simpleFormalParameter(Keyword.VAR, "v")]),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'int get foo => 0;';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_minimal() {
-    _assertSource(
-        "m() {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            null,
-            null,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'foo() {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_multipleParameters() {
-    _assertSource(
-        "m(var a, var b) {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            null,
-            null,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList([
-              AstTestFactory.simpleFormalParameter(Keyword.VAR, "a"),
-              AstTestFactory.simpleFormalParameter(Keyword.VAR, "b")
-            ]),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'void foo(int a, double b) {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_operator() {
-    _assertSource(
-        "operator +() {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            null,
-            null,
-            Keyword.OPERATOR,
-            AstTestFactory.identifier3("+"),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'operator +(int other) {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_operator_returnType() {
-    _assertSource(
-        "T operator +() {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            AstTestFactory.namedType4("T"),
-            null,
-            Keyword.OPERATOR,
-            AstTestFactory.identifier3("+"),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'int operator +(int other) => 0;';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_returnType() {
-    _assertSource(
-        "T m() {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            AstTestFactory.namedType4("T"),
-            null,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'int foo() => 0;';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_setter() {
-    _assertSource(
-        "set m(var v) {}",
-        AstTestFactory.methodDeclaration2(
-            null,
-            null,
-            Keyword.SET,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList(
-                [AstTestFactory.simpleFormalParameter(Keyword.VAR, "v")]),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'set foo(int _) {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
+  }
+
+  void test_visitMethodDeclaration_setter_returnType() {
+    final code = 'void set foo(int _) {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_static() {
-    _assertSource(
-        "static m() {}",
-        AstTestFactory.methodDeclaration2(
-            Keyword.STATIC,
-            null,
-            null,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'static foo() {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_static_returnType() {
-    _assertSource(
-        "static T m() {}",
-        AstTestFactory.methodDeclaration2(
-            Keyword.STATIC,
-            AstTestFactory.namedType4("T"),
-            null,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'static void foo() {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_typeParameters() {
-    _assertSource(
-        "m<E>() {}",
-        AstTestFactory.methodDeclaration3(
-            null,
-            null,
-            null,
-            null,
-            AstTestFactory.identifier3("m"),
-            AstTestFactory.typeParameterList(['E']),
-            AstTestFactory.formalParameterList(),
-            AstTestFactory.blockFunctionBody2()));
+    final code = 'void foo<T>() {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodDeclaration_withMetadata() {
-    MethodDeclaration declaration = AstTestFactory.methodDeclaration2(
-        null,
-        null,
-        null,
-        null,
-        AstTestFactory.identifier3("m"),
-        AstTestFactory.formalParameterList(),
-        AstTestFactory.blockFunctionBody2());
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated m() {}", declaration);
+    final code = '@deprecated void foo() {}';
+    final findNode = _parseStringToFindNode('''
+class A {
+  $code
+}
+''');
+    _assertSource(code, findNode.methodDeclaration(code));
   }
 
   void test_visitMethodInvocation_conditional() {
@@ -2804,10 +2697,9 @@
   }
 
   void test_visitPartDirective_withMetadata() {
-    PartDirective directive = AstTestFactory.partDirective2("a.dart");
-    directive.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated part 'a.dart';", directive);
+    final code = '@deprecated part "a.dart";';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.part(code));
   }
 
   void test_visitPartOfDirective_name() {
@@ -2823,11 +2715,9 @@
   }
 
   void test_visitPartOfDirective_withMetadata() {
-    PartOfDirective directive = AstTestFactory.partOfDirective(
-        AstTestFactory.libraryIdentifier2(["l"]));
-    directive.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated part of l;", directive);
+    final code = '@deprecated part of my.lib;';
+    final findNode = _parseStringToFindNode(code);
+    _assertSource(code, findNode.partOf(code));
   }
 
   void test_visitPositionalFormalParameter() {
@@ -3096,11 +2986,11 @@
   }
 
   void test_visitSimpleFormalParameter_annotation() {
-    SimpleFormalParameter parameter =
-        AstTestFactory.simpleFormalParameter3('x');
-    parameter.metadata
-        .add(AstTestFactory.annotation(AstTestFactory.identifier3("A")));
-    _assertSource('@A x', parameter);
+    final code = '@deprecated int x';
+    final findNode = _parseStringToFindNode('''
+void f($code) {}
+''');
+    _assertSource(code, findNode.simpleFormalParameter(code));
   }
 
   void test_visitSimpleFormalParameter_keyword() {
@@ -3193,10 +3083,13 @@
   }
 
   void test_visitSuperFormalParameter_annotation() {
-    SuperFormalParameter parameter = AstTestFactory.superFormalParameter2('f');
-    parameter.metadata
-        .add(AstTestFactory.annotation(AstTestFactory.identifier3("A")));
-    _assertSource('@A super.f', parameter);
+    final code = '@deprecated super.foo';
+    final findNode = _parseStringToFindNode('''
+class A {
+  A($code);
+}
+''');
+    _assertSource(code, findNode.superFormalParameter(code));
   }
 
   void test_visitSuperFormalParameter_functionTyped() {
@@ -3251,70 +3144,109 @@
   }
 
   void test_visitSwitchCase_multipleLabels() {
-    _assertSource(
-        "l1: l2: case a: {}",
-        AstTestFactory.switchCase2(
-            [AstTestFactory.label2("l1"), AstTestFactory.label2("l2")],
-            AstTestFactory.identifier3("a"),
-            [AstTestFactory.block()]));
+    final code = 'l1: l2: case a: {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchCase(code));
   }
 
   void test_visitSwitchCase_multipleStatements() {
-    _assertSource(
-        "case a: {} {}",
-        AstTestFactory.switchCase(AstTestFactory.identifier3("a"),
-            [AstTestFactory.block(), AstTestFactory.block()]));
+    final code = 'case a: foo(); bar();';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchCase(code));
   }
 
   void test_visitSwitchCase_noLabels() {
-    _assertSource(
-        "case a: {}",
-        AstTestFactory.switchCase(
-            AstTestFactory.identifier3("a"), [AstTestFactory.block()]));
+    final code = 'case a: {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchCase(code));
   }
 
   void test_visitSwitchCase_singleLabel() {
-    _assertSource(
-        "l1: case a: {}",
-        AstTestFactory.switchCase2([AstTestFactory.label2("l1")],
-            AstTestFactory.identifier3("a"), [AstTestFactory.block()]));
+    final code = 'l1: case a: {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchCase(code));
   }
 
   void test_visitSwitchDefault_multipleLabels() {
-    _assertSource(
-        "l1: l2: default: {}",
-        AstTestFactory.switchDefault(
-            [AstTestFactory.label2("l1"), AstTestFactory.label2("l2")],
-            [AstTestFactory.block()]));
+    final code = 'l1: l2: default: {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchDefault(code));
   }
 
   void test_visitSwitchDefault_multipleStatements() {
-    _assertSource(
-        "default: {} {}",
-        AstTestFactory.switchDefault2(
-            [AstTestFactory.block(), AstTestFactory.block()]));
+    final code = 'default: foo(); bar();';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchDefault(code));
   }
 
   void test_visitSwitchDefault_noLabels() {
-    _assertSource(
-        "default: {}", AstTestFactory.switchDefault2([AstTestFactory.block()]));
+    final code = 'default: {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchDefault(code));
   }
 
   void test_visitSwitchDefault_singleLabel() {
-    _assertSource(
-        "l1: default: {}",
-        AstTestFactory.switchDefault(
-            [AstTestFactory.label2("l1")], [AstTestFactory.block()]));
+    final code = 'l1: default: {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  switch (x) {
+    $code
+  }
+}
+''');
+    _assertSource(code, findNode.switchDefault(code));
   }
 
   void test_visitSwitchStatement() {
-    _assertSource(
-        "switch (a) {case 'b': {} default: {}}",
-        AstTestFactory.switchStatement(AstTestFactory.identifier3("a"), [
-          AstTestFactory.switchCase(
-              AstTestFactory.string2("b"), [AstTestFactory.block()]),
-          AstTestFactory.switchDefault2([AstTestFactory.block()])
-        ]));
+    final code = 'switch (x) {case 0: foo(); default: bar();}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  $code
+}
+''');
+    _assertSource(code, findNode.switchStatement(code));
   }
 
   void test_visitSymbolLiteral_multiple() {
@@ -3389,10 +3321,13 @@
   }
 
   void test_visitTryStatement_finally() {
-    _assertSource(
-        "try {} finally {}",
-        AstTestFactory.tryStatement(
-            AstTestFactory.block(), AstTestFactory.block()));
+    final code = 'try {} finally {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  $code
+}
+''');
+    _assertSource(code, findNode.tryStatement(code));
   }
 
   void test_visitTypeArgumentList_multiple() {
@@ -3458,10 +3393,11 @@
   }
 
   void test_visitTypeParameter_withMetadata() {
-    TypeParameter parameter = AstTestFactory.typeParameter("E");
-    parameter.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated E", parameter);
+    final code = '@deprecated T';
+    final findNode = _parseStringToFindNode('''
+class A<$code> {}
+''');
+    _assertSource(code, findNode.typeParameter(code));
   }
 
   void test_visitTypeParameter_withoutExtends() {
@@ -3487,13 +3423,6 @@
     _assertSource("a", AstTestFactory.variableDeclaration("a"));
   }
 
-  void test_visitVariableDeclaration_withMetadata() {
-    VariableDeclaration declaration = AstTestFactory.variableDeclaration("a");
-    declaration.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated a", declaration);
-  }
-
   void test_visitVariableDeclarationList_const_type() {
     _assertSource(
         "const C a, b",
@@ -3513,17 +3442,6 @@
         ]));
   }
 
-  void test_visitVariableDeclarationList_final_withMetadata() {
-    VariableDeclarationList declarationList =
-        AstTestFactory.variableDeclarationList2(Keyword.FINAL, [
-      AstTestFactory.variableDeclaration("a"),
-      AstTestFactory.variableDeclaration("b")
-    ]);
-    declarationList.metadata.add(
-        AstTestFactory.annotation(AstTestFactory.identifier3("deprecated")));
-    _assertSource("@deprecated final a, b", declarationList);
-  }
-
   void test_visitVariableDeclarationList_type() {
     _assertSource(
         "C a, b",
@@ -3553,10 +3471,13 @@
   }
 
   void test_visitWhileStatement() {
-    _assertSource(
-        "while (c) {}",
-        AstTestFactory.whileStatement(
-            AstTestFactory.identifier3("c"), AstTestFactory.block()));
+    final code = 'while (true) {}';
+    final findNode = _parseStringToFindNode('''
+void f() {
+  $code
+}
+''');
+    _assertSource(code, findNode.whileStatement(code));
   }
 
   void test_visitWithClause_multiple() {
diff --git a/pkg/analyzer/test/src/dart/constant/utilities_test.dart b/pkg/analyzer/test/src/dart/constant/utilities_test.dart
index 8a22db8..6d3619b 100644
--- a/pkg/analyzer/test/src/dart/constant/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/utilities_test.dart
@@ -5,254 +5,21 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../../generated/test_support.dart';
-
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(ConstantFinderTest);
     defineReflectiveTests(ReferenceFinderTest);
   });
 }
 
 @reflectiveTest
-class ConstantFinderTest {
-  late final AstNode _node;
-  late final TypeProvider _typeProvider;
-  late final Source _source;
-
-  void setUp() {
-    _typeProvider = TestTypeProvider();
-    _source = TestSource();
-  }
-
-  /// Test an annotation that consists solely of an identifier (and hence
-  /// represents a reference to a compile-time constant variable).
-  void test_visitAnnotation_constantVariable() {
-    var compilationUnitElement =
-        ElementFactory.compilationUnit(source: _source);
-    ElementFactory.library(_AnalysisContextMock(), 'L')
-        .definingCompilationUnit = compilationUnitElement;
-    ElementAnnotationImpl elementAnnotation =
-        ElementAnnotationImpl(compilationUnitElement);
-    var annotation = AstTestFactory.annotation(AstTestFactory.identifier3('x'));
-    _node = elementAnnotation.annotationAst = annotation
-      ..elementAnnotation = elementAnnotation;
-    expect(_findAnnotations(), contains(_node));
-  }
-
-  /// Test an annotation that represents the invocation of a constant
-  /// constructor.
-  void test_visitAnnotation_invocation() {
-    var compilationUnitElement =
-        ElementFactory.compilationUnit(source: _source);
-    ElementFactory.library(_AnalysisContextMock(), 'L')
-        .definingCompilationUnit = compilationUnitElement;
-    ElementAnnotationImpl elementAnnotation =
-        ElementAnnotationImpl(compilationUnitElement);
-    var annotation = AstTestFactory.annotation2(
-        AstTestFactory.identifier3('A'), null, AstTestFactory.argumentList());
-    _node = elementAnnotation.annotationAst = annotation
-      ..elementAnnotation = elementAnnotation;
-    expect(_findAnnotations(), contains(_node));
-  }
-
-  void test_visitAnnotation_partOf() {
-    // Analyzer ignores annotations on "part of" directives.
-    Annotation annotation = AstTestFactory.annotation2(
-        AstTestFactory.identifier3('A'), null, AstTestFactory.argumentList());
-    _node = AstTestFactory.partOfDirective2(<Annotation>[annotation],
-        AstTestFactory.libraryIdentifier2(<String>['L']));
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitConstructorDeclaration_const() {
-    ConstructorElement element = _setupConstructorDeclaration("A", true);
-    expect(_findConstants(), contains(element));
-  }
-
-  void test_visitConstructorDeclaration_nonConst() {
-    _setupConstructorDeclaration("A", false);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_const() {
-    VariableElement element = _setupVariableDeclaration("v", true, true);
-    expect(_findConstants(), contains(element));
-  }
-
-  void test_visitVariableDeclaration_final_inClass() {
-    _setupFieldDeclaration('C', 'f', Keyword.FINAL);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_final_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
-        hasConstConstructor: true);
-    expect(_findConstants(), contains(field.declaredElement));
-  }
-
-  void test_visitVariableDeclaration_final_outsideClass() {
-    _setupVariableDeclaration('v', false, true, isFinal: true);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_noInitializer() {
-    _setupVariableDeclaration("v", true, false);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_nonConst() {
-    _setupVariableDeclaration("v", false, true);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_static_const_inClass() {
-    VariableDeclaration field =
-        _setupFieldDeclaration('C', 'f', Keyword.CONST, isStatic: true);
-    expect(_findConstants(), contains(field.declaredElement));
-  }
-
-  void
-      test_visitVariableDeclaration_static_const_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.CONST,
-        isStatic: true, hasConstConstructor: true);
-    expect(_findConstants(), contains(field.declaredElement));
-  }
-
-  void
-      test_visitVariableDeclaration_static_final_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
-        isStatic: true, hasConstConstructor: true);
-    expect(_findConstants(), isNot(contains(field.declaredElement)));
-  }
-
-  void
-      test_visitVariableDeclaration_uninitialized_final_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
-        isInitialized: false, hasConstConstructor: true);
-    expect(_findConstants(), isNot(contains(field.declaredElement)));
-  }
-
-  void test_visitVariableDeclaration_uninitialized_static_const_inClass() {
-    _setupFieldDeclaration('C', 'f', Keyword.CONST,
-        isStatic: true, isInitialized: false);
-    expect(_findConstants(), isEmpty);
-  }
-
-  List<Annotation> _findAnnotations() {
-    Set<Annotation> annotations = <Annotation>{};
-    for (ConstantEvaluationTarget target in _findConstants()) {
-      if (target is ElementAnnotationImpl) {
-        expect(target.source, same(_source));
-        annotations.add(target.annotationAst);
-      }
-    }
-    return List<Annotation>.from(annotations);
-  }
-
-  List<ConstantEvaluationTarget> _findConstants() {
-    ConstantFinder finder = ConstantFinder();
-    _node.accept(finder);
-    List<ConstantEvaluationTarget> constants = finder.constantsToCompute;
-    expect(constants, isNotNull);
-    return constants;
-  }
-
-  ConstructorElement _setupConstructorDeclaration(String name, bool isConst) {
-    var constKeyword = isConst ? Keyword.CONST : null;
-    var constructorDeclaration = AstTestFactory.constructorDeclaration2(
-        constKeyword,
-        null,
-        AstTestFactory.identifier3(name),
-        null,
-        AstTestFactory.formalParameterList(),
-        [],
-        AstTestFactory.blockFunctionBody2());
-    ClassElement classElement = ElementFactory.classElement2(name);
-    ConstructorElement element =
-        ElementFactory.constructorElement(classElement, name, isConst);
-    constructorDeclaration.declaredElement = element;
-    _node = constructorDeclaration;
-    return element;
-  }
-
-  VariableDeclaration _setupFieldDeclaration(
-      String className, String fieldName, Keyword keyword,
-      {bool isInitialized = true,
-      bool isStatic = false,
-      bool hasConstConstructor = false}) {
-    var variableDeclaration = isInitialized
-        ? AstTestFactory.variableDeclaration2(
-            fieldName, AstTestFactory.integer(0))
-        : AstTestFactory.variableDeclaration(fieldName);
-    var fieldElement = ElementFactory.fieldElement(
-        fieldName,
-        isStatic,
-        keyword == Keyword.FINAL,
-        keyword == Keyword.CONST,
-        _typeProvider.intType);
-    variableDeclaration.declaredElement = fieldElement;
-    FieldDeclaration fieldDeclaration = AstTestFactory.fieldDeclaration2(
-        isStatic, keyword, <VariableDeclaration>[variableDeclaration]);
-    var classDeclaration = AstTestFactory.classDeclaration(
-        null, className, null, null, null, null);
-    classDeclaration.members.add(fieldDeclaration);
-    _node = classDeclaration;
-    ClassElementImpl classElement = ElementFactory.classElement2(className);
-    classElement.fields = <FieldElement>[fieldElement];
-    classDeclaration.declaredElement = classElement;
-    if (hasConstConstructor) {
-      var constructorDeclaration = AstTestFactory.constructorDeclaration2(
-          Keyword.CONST,
-          null,
-          AstTestFactory.identifier3(className),
-          null,
-          AstTestFactory.formalParameterList(),
-          [],
-          AstTestFactory.blockFunctionBody2());
-      classDeclaration.members.add(constructorDeclaration);
-      ConstructorElement constructorElement =
-          ElementFactory.constructorElement(classElement, '', true);
-      constructorDeclaration.declaredElement = constructorElement;
-      classElement.constructors = <ConstructorElement>[constructorElement];
-    } else {
-      classElement.constructors = const <ConstructorElement>[];
-    }
-    return variableDeclaration;
-  }
-
-  VariableElement _setupVariableDeclaration(
-      String name, bool isConst, bool isInitialized,
-      {isFinal = false}) {
-    var variableDeclaration = isInitialized
-        ? AstTestFactory.variableDeclaration2(name, AstTestFactory.integer(0))
-        : AstTestFactory.variableDeclaration(name);
-    VariableElement element = ElementFactory.localVariableElement2(name);
-    variableDeclaration.declaredElement = element;
-    var keyword = isConst
-        ? Keyword.CONST
-        : isFinal
-            ? Keyword.FINAL
-            : null;
-    AstTestFactory.variableDeclarationList2(keyword, [variableDeclaration]);
-    _node = variableDeclaration;
-    return element;
-  }
-}
-
-@reflectiveTest
 class ReferenceFinderTest {
   late final Element _tail;
   final List<ConstantEvaluationTarget> _dependencies = [];
@@ -330,8 +97,3 @@
     node.accept(referenceFinder);
   }
 }
-
-class _AnalysisContextMock implements AnalysisContext {
-  @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/analyzer/test/src/dart/element/class_element_test.dart b/pkg/analyzer/test/src/dart/element/class_element_test.dart
index 744578e..7270987 100644
--- a/pkg/analyzer/test/src/dart/element/class_element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/class_element_test.dart
@@ -74,13 +74,6 @@
     _assertIsEnumLike(findElement.class_('A'), false);
   }
 
-  test_isEnumLike_false_isMixin() async {
-    await assertNoErrorsInCode('''
-mixin M {}
-''');
-    _assertIsEnumLike(findElement.mixin('M'), false);
-  }
-
   test_isEnumLike_true() async {
     await assertNoErrorsInCode('''
 class A {
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 98b3f3b..3eb5228 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -289,20 +289,24 @@
     }
   }
 
-  void _writeClassElement(ClassElement e) {
+  void _writeClassElement(InterfaceElement e) {
     _writeIndentedLine(() {
-      _writeIf(e.isAbstract && !e.isMixin, 'abstract ');
-      _writeIf(e.isMacro, 'macro ');
+      if (e is ClassElement) {
+        _writeIf(e.isAbstract && !e.isMixin, 'abstract ');
+        _writeIf(e.isMacro, 'macro ');
+      }
       _writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
 
-      if (e.isEnum) {
+      if (e is EnumElement) {
         buffer.write('enum ');
-      } else if (e.isMixin) {
+      } else if (e is MixinElement) {
         buffer.write('mixin ');
       } else {
         buffer.write('class ');
       }
-      _writeIf(e.isMixinApplication, 'alias ');
+      if (e is ClassElement) {
+        _writeIf(e.isMixinApplication, 'alias ');
+      }
 
       _writeName(e);
     });
@@ -313,13 +317,18 @@
       _writeCodeRange(e);
       _writeTypeParameterElements(e.typeParameters);
 
-      var supertype = e.supertype;
+      InterfaceType? supertype;
+      if (e is ClassElement) {
+        supertype = e.supertype;
+      } else if (e is EnumElement) {
+        supertype = e.supertype;
+      }
       if (supertype != null &&
           (supertype.element.name != 'Object' || e.mixins.isNotEmpty)) {
         _writeType('supertype', supertype);
       }
 
-      if (e.isMixin) {
+      if (e is MixinElement) {
         var superclassConstraints = e.superclassConstraints;
         if (superclassConstraints.isEmpty) {
           throw StateError('At least Object is expected.');
@@ -333,7 +342,7 @@
       _writeElements('fields', e.fields, _writePropertyInducingElement);
 
       var constructors = e.constructors;
-      if (e.isMixin) {
+      if (e is MixinElement) {
         expect(constructors, isEmpty);
       } else {
         expect(constructors, isNotEmpty);
@@ -1026,9 +1035,9 @@
 
   void _writeUnitElement(CompilationUnitElement e) {
     _writeElements('classes', e.classes, _writeClassElement);
-    _writeElements('enums', e.enums, _writeClassElement);
+    _writeElements('enums', e.enums2, _writeClassElement);
     _writeElements('extensions', e.extensions, _writeExtensionElement);
-    _writeElements('mixins', e.mixins, _writeClassElement);
+    _writeElements('mixins', e.mixins2, _writeClassElement);
     _writeElements('typeAliases', e.typeAliases, _writeTypeAliasElement);
     _writeElements(
       'topLevelVariables',
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index f86beeb..6fa83b4 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -32467,7 +32467,7 @@
 
     // We intentionally ask `mixins` directly, to check that we can ask them
     // separately, without asking classes.
-    var mixins = library.definingCompilationUnit.mixins;
+    var mixins = library.definingCompilationUnit.mixins2;
     expect(mixins, hasLength(1));
     expect(mixins[0].name, 'M');
   }
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index a63e5b4..1a3ee99 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -19398,11 +19398,19 @@
 The analyzer produces this diagnostic when a private declaration isn't
 referenced in the library that contains the declaration. The following
 kinds of declarations are analyzed:
-- Private top-level declarations, such as classes, enums, mixins, typedefs,
-  top-level variables, and top-level functions
-- Private static and instance methods
+- Private top-level declarations and all of their members
+- Private members of public declarations
 - Optional parameters of private functions for which a value is never
-  passed, even when the parameter doesn't have a private name
+  passed
+
+Not all references to an element will mark it as "used":
+- Assigning a value to a top-level variable (with a standard `=`
+  assignment, or a null-aware `??=` assignment) does not count as using
+  it.
+- Refering to an element in a doc comment reference does not count as
+  using it.
+- Refering to a class, mixin, or enum in the right side of an `is`
+  expression does not count as using it.
 
 #### Example
 
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 09bae68..06f1d0f 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -3032,11 +3032,11 @@
     var path = convertPath('/home/test/lib/test.dart');
     addSource(path, content);
 
-    ClassElement? targetElement;
+    InterfaceElement? targetElement;
     {
       var unitResult = (await resolveFile(path)).unit;
       if (targetMixinName != null) {
-        targetElement = unitResult.declaredElement!.mixins
+        targetElement = unitResult.declaredElement!.mixins2
             .firstWhere((e) => e.name == targetMixinName);
       } else {
         targetElement = unitResult.declaredElement!.classes
diff --git a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
index 8873cd0..5b04212 100644
--- a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
+++ b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
@@ -98,13 +98,18 @@
 
   /// Get all the decorated immediate supertypes of the non-migrated class
   /// [class_].
-  Iterable<DecoratedType> getImmediateSupertypes(ClassElement class_) {
+  Iterable<DecoratedType> getImmediateSupertypes(InterfaceElement class_) {
     var allSupertypes = <DartType>[];
-    var supertype = class_.supertype;
+    InterfaceType? supertype;
+    if (class_ is ClassElement) {
+      supertype = class_.supertype;
+    }
     if (supertype != null) {
       allSupertypes.add(supertype);
     }
-    allSupertypes.addAll(class_.superclassConstraints);
+    if (class_ is MixinElement) {
+      allSupertypes.addAll(class_.superclassConstraints);
+    }
     allSupertypes.addAll(class_.preMigrationInterfaces);
     allSupertypes.addAll(class_.mixins);
     var type = class_.thisType;
@@ -119,7 +124,7 @@
   }
 }
 
-extension on ClassElement {
+extension on InterfaceElement {
   List<InterfaceType> get preMigrationInterfaces {
     var previousElementTypeProvider = ElementTypeProvider.current;
     try {
diff --git a/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart b/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
index 519bd12..1baa2ce 100644
--- a/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
@@ -21,7 +21,7 @@
 
   /// Cache for speeding up the computation of
   /// [_getGenericSupertypeDecorations].
-  final Map<ClassElement, Map<ClassElement, DecoratedType>>
+  final Map<InterfaceElement, Map<ClassElement, DecoratedType>>
       _genericSupertypeDecorations = {};
 
   DecoratedClassHierarchy(this._variables, this._graph);
@@ -52,7 +52,7 @@
   /// because the relationship between a class and its superclass is not
   /// nullable.
   DecoratedType getDecoratedSupertype(
-      ClassElement class_, InterfaceElement superclass) {
+      InterfaceElement class_, InterfaceElement superclass) {
     assert(!(class_.library.isDartCore && class_.name == 'Null'));
     if (superclass.typeParameters.isEmpty) {
       return DecoratedType(
@@ -70,7 +70,7 @@
   /// Computes a map whose keys are all the superclasses of [class_], and whose
   /// values indicate how [class_] implements each superclass.
   Map<ClassElement, DecoratedType> _getGenericSupertypeDecorations(
-      ClassElement class_) {
+      InterfaceElement class_) {
     var decorations = _genericSupertypeDecorations[class_];
     if (decorations == null) {
       // Call ourselves recursively to compute how each of [class_]'s direct
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 681852f..1ff963c 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -49,7 +49,7 @@
   final _decoratedElementTypes = <Element?, DecoratedType?>{};
 
   final _decoratedDirectSupertypes =
-      <ClassElement, Map<ClassElement, DecoratedType?>>{};
+      <InterfaceElement, Map<ClassElement, DecoratedType?>>{};
 
   final _decoratedTypeAnnotations = <Source?, Map<int, DecoratedType>>{};
 
@@ -76,7 +76,7 @@
   /// Given a [class_], gets the decorated type information for the superclasses
   /// it directly implements/extends/etc.
   Map<ClassElement, DecoratedType?> decoratedDirectSupertypes(
-      ClassElement class_) {
+      InterfaceElement class_) {
     return _decoratedDirectSupertypes[class_] ??=
         _decorateDirectSupertypes(class_);
   }
@@ -418,7 +418,7 @@
   /// Creates an entry [_decoratedDirectSupertypes] for an already-migrated
   /// class.
   Map<ClassElement, DecoratedType> _decorateDirectSupertypes(
-      ClassElement class_) {
+      InterfaceElement class_) {
     var result = <ClassElement, DecoratedType>{};
     for (var decoratedSupertype
         in _alreadyMigratedCodeDecorator.getImmediateSupertypes(class_)) {
diff --git a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
index eefd869..57d6285 100644
--- a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
+++ b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
@@ -427,7 +427,7 @@
       'mixin C on num {}',
     );
     var unitElement = withUnit.unitElement;
-    var mixin_ = unitElement.mixins.single;
+    var mixin_ = unitElement.mixins2.single;
 
     var withElement = withUnit.withElement(mixin_);
 
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 1f097a6..2ba066f 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -8296,7 +8296,7 @@
 
   @override
   DecoratedType getDecoratedSupertype(
-      ClassElement class_, InterfaceElement superclass) {
+      InterfaceElement class_, InterfaceElement superclass) {
     throw UnimplementedError('TODO(paulberry)');
   }
 }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 64576491..02122a3 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -662,6 +662,20 @@
   }
 }
 
+void Assembler::LoadSImmediate(VRegister vd, float imms) {
+  int32_t imm32 = bit_cast<int32_t, float>(imms);
+  if (imm32 == 0) {
+    veor(vd, vd, vd);
+  } else if (constant_pool_allowed()) {
+    intptr_t index = object_pool_builder().FindImmediate(imm32);
+    intptr_t offset = target::ObjectPool::element_offset(index);
+    LoadSFromOffset(vd, PP, offset);
+  } else {
+    LoadImmediate(TMP, imm32);
+    fmovsr(vd, TMP);
+  }
+}
+
 void Assembler::LoadDImmediate(VRegister vd, double immd) {
   if (fmovdi(vd, immd)) return;
 
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index ea47f52..56b0fda 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -2066,6 +2066,7 @@
     LoadImmediate(reg, imm.value());
   }
 
+  void LoadSImmediate(VRegister reg, float immd);
   void LoadDImmediate(VRegister reg, double immd);
   void LoadQImmediate(VRegister reg, simd128_value_t immq);
 
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 51c1fa9..73d84a5 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2199,6 +2199,13 @@
   addl(dest, inc_imm);
 }
 
+void Assembler::LoadSImmediate(XmmRegister dst, float value) {
+  int32_t constant = bit_cast<int32_t, float>(value);
+  pushl(Immediate(constant));
+  movss(dst, Address(ESP, 0));
+  addl(ESP, Immediate(target::kWordSize));
+}
+
 void Assembler::LoadDImmediate(XmmRegister dst, double value) {
   // TODO(5410843): Need to have a code constants table.
   int64_t constant = bit_cast<int64_t, double>(value);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index 7ef5339..77b453b 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -759,6 +759,7 @@
     LoadImmediate(reg, immediate.value());
   }
 
+  void LoadSImmediate(XmmRegister dst, float value);
   void LoadDImmediate(XmmRegister dst, double value);
 
   void Drop(intptr_t stack_elements);
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.cc b/runtime/vm/compiler/assembler/assembler_riscv.cc
index 10beeac..08a4b28 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv.cc
@@ -3351,6 +3351,18 @@
   }
 }
 
+void Assembler::LoadSImmediate(FRegister reg, float imms) {
+  int32_t imm = bit_cast<int32_t, float>(imms);
+  if (imm == 0) {
+    fmvwx(reg, ZR);  // bit_cast uint32_t -> float
+  } else {
+    ASSERT(constant_pool_allowed());
+    intptr_t index = object_pool_builder().FindImmediate(imm);
+    intptr_t offset = target::ObjectPool::element_offset(index);
+    LoadSFromOffset(reg, PP, offset);
+  }
+}
+
 void Assembler::LoadDImmediate(FRegister reg, double immd) {
   int64_t imm = bit_cast<int64_t, double>(immd);
   if (imm == 0) {
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.h b/runtime/vm/compiler/assembler/assembler_riscv.h
index cefa220..18eeb4a 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.h
+++ b/runtime/vm/compiler/assembler/assembler_riscv.h
@@ -432,6 +432,8 @@
   void feqs(Register rd, FRegister rs1, FRegister rs2);
   void flts(Register rd, FRegister rs1, FRegister rs2);
   void fles(Register rd, FRegister rs1, FRegister rs2);
+  void fgts(Register rd, FRegister rs1, FRegister rs2) { flts(rd, rs2, rs1); }
+  void fges(Register rd, FRegister rs1, FRegister rs2) { fles(rd, rs2, rs1); }
   void fclasss(Register rd, FRegister rs1);
   // int32_t <- float
   void fcvtws(Register rd, FRegister rs1, RoundingMode rounding = RNE);
@@ -517,6 +519,8 @@
   void feqd(Register rd, FRegister rs1, FRegister rs2);
   void fltd(Register rd, FRegister rs1, FRegister rs2);
   void fled(Register rd, FRegister rs1, FRegister rs2);
+  void fgtd(Register rd, FRegister rs1, FRegister rs2) { fltd(rd, rs2, rs1); }
+  void fged(Register rd, FRegister rs1, FRegister rs2) { fled(rd, rs2, rs1); }
   void fclassd(Register rd, FRegister rs1);
   // int32_t <- double
   void fcvtwd(Register rd, FRegister rs1, RoundingMode rounding = RNE);
@@ -1018,6 +1022,9 @@
                              Register index);
   void LoadSFromOffset(FRegister dest, Register base, int32_t offset);
   void LoadDFromOffset(FRegister dest, Register base, int32_t offset);
+  void LoadSFieldFromOffset(FRegister dest, Register base, int32_t offset) {
+    LoadSFromOffset(dest, base, offset - kHeapObjectTag);
+  }
   void LoadDFieldFromOffset(FRegister dest, Register base, int32_t offset) {
     LoadDFromOffset(dest, base, offset - kHeapObjectTag);
   }
@@ -1043,6 +1050,9 @@
     sx(ZR, address);
   }
   void StoreSToOffset(FRegister src, Register base, int32_t offset);
+  void StoreSFieldToOffset(FRegister src, Register base, int32_t offset) {
+    StoreSToOffset(src, base, offset - kHeapObjectTag);
+  }
   void StoreDToOffset(FRegister src, Register base, int32_t offset);
   void StoreDFieldToOffset(FRegister src, Register base, int32_t offset) {
     StoreDToOffset(src, base, offset - kHeapObjectTag);
@@ -1182,6 +1192,7 @@
   // Note: the function never clobbers TMP, TMP2 scratch registers.
   void LoadImmediate(Register reg, intx_t imm);
 
+  void LoadSImmediate(FRegister reg, float imms);
   void LoadDImmediate(FRegister reg, double immd);
   void LoadQImmediate(FRegister reg, simd128_value_t immq);
 
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index bfed044..b7e098c 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1394,6 +1394,17 @@
   }
 }
 
+void Assembler::LoadSImmediate(FpuRegister dst, float immediate) {
+  int32_t bits = bit_cast<int32_t>(immediate);
+  if (bits == 0) {
+    xorps(dst, dst);
+  } else {
+    intptr_t index = object_pool_builder().FindImmediate(bits);
+    LoadUnboxedSingle(
+        dst, PP, target::ObjectPool::element_offset(index) - kHeapObjectTag);
+  }
+}
+
 void Assembler::LoadDImmediate(FpuRegister dst, double immediate) {
   int64_t bits = bit_cast<int64_t>(immediate);
   if (bits == 0) {
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index eafff9b..d0b48f8 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -787,6 +787,7 @@
   void LoadImmediate(Register reg, int32_t immediate) {
     LoadImmediate(reg, Immediate(immediate));
   }
+  void LoadSImmediate(FpuRegister dst, float immediate);
   void LoadDImmediate(FpuRegister dst, double immediate);
   void LoadQImmediate(FpuRegister dst, simd128_value_t immediate);
 
@@ -1082,6 +1083,9 @@
     movq(Address(base, offset), src);
   }
 
+  void LoadUnboxedSingle(FpuRegister dst, Register base, int32_t offset) {
+    movss(dst, Address(base, offset));
+  }
   void LoadUnboxedDouble(FpuRegister dst, Register base, int32_t offset) {
     movsd(dst, Address(base, offset));
   }
diff --git a/runtime/vm/compiler/backend/block_builder.h b/runtime/vm/compiler/backend/block_builder.h
index 4a36631..de4c656 100644
--- a/runtime/vm/compiler/backend/block_builder.h
+++ b/runtime/vm/compiler/backend/block_builder.h
@@ -136,6 +136,8 @@
     entry_->AsJoinEntry()->InsertPhi(phi);
   }
 
+  Instruction* last() const { return current_; }
+
  private:
   static CompileType* TypeForRepresentation(Representation rep) {
     switch (rep) {
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index 8456490..8e53015 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -872,6 +872,16 @@
   }
 }
 
+void ConstantPropagator::VisitBoolToInt(BoolToIntInstr* instr) {
+  // TODO(riscv)
+  SetValue(instr, non_constant_);
+}
+
+void ConstantPropagator::VisitIntToBool(IntToBoolInstr* instr) {
+  // TODO(riscv)
+  SetValue(instr, non_constant_);
+}
+
 void ConstantPropagator::VisitInstanceOf(InstanceOfInstr* instr) {
   Definition* def = instr->value()->definition();
   const Object& value = def->constant_value();
@@ -1216,8 +1226,27 @@
   VisitUnaryIntegerOp(instr);
 }
 
+static bool IsIntegerOrDouble(const Object& value) {
+  return value.IsInteger() || value.IsDouble();
+}
+
+static double ToDouble(const Object& value) {
+  return value.IsInteger() ? Integer::Cast(value).AsDoubleValue()
+                           : Double::Cast(value).value();
+}
+
 void ConstantPropagator::VisitUnaryDoubleOp(UnaryDoubleOpInstr* instr) {
-  // TODO(kmillikin): Handle unary operations.
+  const Object& value = instr->value()->definition()->constant_value();
+  if (IsUnknown(value)) {
+    return;
+  }
+  if (value.IsDouble()) {
+    const double result_val = Evaluator::EvaluateUnaryDoubleOp(
+        ToDouble(value), instr->op_kind(), instr->representation());
+    const Double& result = Double::ZoneHandle(Double::NewCanonical(result_val));
+    SetValue(instr, result);
+    return;
+  }
   SetValue(instr, non_constant_);
 }
 
@@ -1273,11 +1302,6 @@
   SetValue(instr, non_constant_);
 }
 
-void ConstantPropagator::VisitDoubleToDouble(DoubleToDoubleInstr* instr) {
-  // TODO(kmillikin): Handle conversion.
-  SetValue(instr, non_constant_);
-}
-
 void ConstantPropagator::VisitDoubleToFloat(DoubleToFloatInstr* instr) {
   // TODO(kmillikin): Handle conversion.
   SetValue(instr, non_constant_);
@@ -1288,6 +1312,11 @@
   SetValue(instr, non_constant_);
 }
 
+void ConstantPropagator::VisitFloatCompare(FloatCompareInstr* instr) {
+  // TODO(riscv)
+  SetValue(instr, non_constant_);
+}
+
 void ConstantPropagator::VisitInvokeMathCFunction(
     InvokeMathCFunctionInstr* instr) {
   // TODO(kmillikin): Handle conversion.
@@ -1303,6 +1332,25 @@
   SetValue(instr, non_constant_);
 }
 
+void ConstantPropagator::VisitUnboxLane(UnboxLaneInstr* instr) {
+  if (BoxLanesInstr* box = instr->value()->definition()->AsBoxLanes()) {
+    const Object& value =
+        box->InputAt(instr->lane())->definition()->constant_value();
+    if (IsUnknown(value)) {
+      return;
+    }
+    SetValue(instr, value);
+    return;
+  }
+
+  SetValue(instr, non_constant_);
+}
+
+void ConstantPropagator::VisitBoxLanes(BoxLanesInstr* instr) {
+  // TODO(riscv)
+  SetValue(instr, non_constant_);
+}
+
 void ConstantPropagator::VisitConstant(ConstantInstr* instr) {
   SetValue(instr, instr->value());
 }
@@ -1321,15 +1369,6 @@
   UNREACHABLE();
 }
 
-static bool IsIntegerOrDouble(const Object& value) {
-  return value.IsInteger() || value.IsDouble();
-}
-
-static double ToDouble(const Object& value) {
-  return value.IsInteger() ? Integer::Cast(value).AsDoubleValue()
-                           : Double::Cast(value).value();
-}
-
 void ConstantPropagator::VisitBinaryDoubleOp(BinaryDoubleOpInstr* instr) {
   const Object& left = instr->left()->definition()->constant_value();
   const Object& right = instr->right()->definition()->constant_value();
@@ -1343,8 +1382,9 @@
   const bool both_are_integers = left.IsInteger() && right.IsInteger();
   if (IsIntegerOrDouble(left) && IsIntegerOrDouble(right) &&
       !both_are_integers) {
-    const double result_val = Evaluator::EvaluateDoubleOp(
-        ToDouble(left), ToDouble(right), instr->op_kind());
+    const double result_val = Evaluator::EvaluateBinaryDoubleOp(
+        ToDouble(left), ToDouble(right), instr->op_kind(),
+        instr->representation());
     const Double& result = Double::ZoneHandle(Double::NewCanonical(result_val));
     SetValue(instr, result);
     return;
@@ -1384,11 +1424,6 @@
   SetValue(instr, non_constant_);
 }
 
-void ConstantPropagator::VisitMathUnary(MathUnaryInstr* instr) {
-  // TODO(kmillikin): Handle Math's unary operations (sqrt, cos, sin).
-  SetValue(instr, non_constant_);
-}
-
 void ConstantPropagator::VisitMathMinMax(MathMinMaxInstr* instr) {
   // TODO(srdjan): Handle min and max.
   SetValue(instr, non_constant_);
diff --git a/runtime/vm/compiler/backend/evaluator.cc b/runtime/vm/compiler/backend/evaluator.cc
index 9ab7d39..2f9e3b3 100644
--- a/runtime/vm/compiler/backend/evaluator.cc
+++ b/runtime/vm/compiler/backend/evaluator.cc
@@ -189,20 +189,91 @@
   return result.ptr();
 }
 
-double Evaluator::EvaluateDoubleOp(const double left,
-                                   const double right,
-                                   Token::Kind token_kind) {
-  switch (token_kind) {
-    case Token::kADD:
-      return left + right;
-    case Token::kSUB:
-      return left - right;
-    case Token::kMUL:
-      return left * right;
-    case Token::kDIV:
-      return left / right;
-    default:
-      UNREACHABLE();
+double Evaluator::EvaluateUnaryDoubleOp(const double value,
+                                        Token::Kind token_kind,
+                                        Representation representation) {
+  // The different set of operations for float32 and float64 is due to the
+  // different set of operations made available by dart:core.double and
+  // dart:typed_data.Float64x2 versus dart:typed_data.Float32x4.
+  if (representation == kUnboxedDouble) {
+    switch (token_kind) {
+      case Token::kABS:
+        return fabs(value);
+      case Token::kNEGATE:
+        return -value;
+      case Token::kSQRT:
+        return sqrt(value);
+      case Token::kSQUARE:
+        return value * value;
+      case Token::kTRUNCATE:
+        return trunc(value);
+      case Token::kFLOOR:
+        return floor(value);
+      case Token::kCEILING:
+        return ceil(value);
+      default:
+        UNREACHABLE();
+    }
+  } else {
+    ASSERT(representation == kUnboxedFloat);
+    switch (token_kind) {
+      case Token::kABS:
+        return fabsf(static_cast<float>(value));
+      case Token::kNEGATE:
+        return -static_cast<float>(value);
+      case Token::kRECIPROCAL:
+        return 1.0f / static_cast<float>(value);
+      case Token::kRECIPROCAL_SQRT:
+        return sqrtf(1.0f / static_cast<float>(value));
+      case Token::kSQRT:
+        return sqrtf(static_cast<float>(value));
+      case Token::kSQUARE:
+        return static_cast<float>(value) * static_cast<float>(value);
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+
+double Evaluator::EvaluateBinaryDoubleOp(const double left,
+                                         const double right,
+                                         Token::Kind token_kind,
+                                         Representation representation) {
+  if (representation == kUnboxedDouble) {
+    switch (token_kind) {
+      case Token::kADD:
+        return left + right;
+      case Token::kSUB:
+        return left - right;
+      case Token::kMUL:
+        return left * right;
+      case Token::kDIV:
+        return left / right;
+      case Token::kMIN:
+        return fmin(left, right);
+      case Token::kMAX:
+        return fmax(left, right);
+      default:
+        UNREACHABLE();
+    }
+  } else {
+    ASSERT(representation == kUnboxedFloat);
+    switch (token_kind) {
+      case Token::kADD:
+        return static_cast<float>(left) + static_cast<float>(right);
+      case Token::kSUB:
+        return static_cast<float>(left) - static_cast<float>(right);
+      case Token::kMUL:
+        return static_cast<float>(left) * static_cast<float>(right);
+      case Token::kDIV:
+        return static_cast<float>(left) / static_cast<float>(right);
+      case Token::kMIN:
+        return fminf(static_cast<float>(left), static_cast<float>(right));
+      case Token::kMAX:
+        return fmaxf(static_cast<float>(left), static_cast<float>(right));
+      default:
+        UNREACHABLE();
+    }
   }
 }
 
diff --git a/runtime/vm/compiler/backend/evaluator.h b/runtime/vm/compiler/backend/evaluator.h
index dca583a..afd05ed 100644
--- a/runtime/vm/compiler/backend/evaluator.h
+++ b/runtime/vm/compiler/backend/evaluator.h
@@ -44,10 +44,16 @@
                                       Representation representation,
                                       Thread* thread);
 
+  // Evaluates a unary double operation and returns the result.
+  static double EvaluateUnaryDoubleOp(const double value,
+                                      Token::Kind token_kind,
+                                      Representation representation);
+
   // Evaluates a binary double operation and returns the result.
-  static double EvaluateDoubleOp(const double left,
-                                 const double right,
-                                 Token::Kind token_kind);
+  static double EvaluateBinaryDoubleOp(const double left,
+                                       const double right,
+                                       Token::Kind token_kind,
+                                       Representation representation);
 
   // Returns whether the value is an int64, and returns the int64 value
   // through the result parameter.
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 95691ce..d167f2d 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -220,6 +220,7 @@
     case kUnboxedInt64:
       return value.IsInteger();
 
+    case kUnboxedFloat:
     case kUnboxedDouble:
       return value.IsInteger() || value.IsDouble();
 
@@ -238,11 +239,13 @@
     return op;
   }
 
-  if (representation == kUnboxedDouble && value.IsInteger()) {
-    // Convert the boxed constant from int to double.
+  if (((representation == kUnboxedFloat) ||
+       (representation == kUnboxedDouble)) &&
+      value.IsInteger()) {
+    // Convert the boxed constant from int to float/double.
     return GetConstant(Double::Handle(Double::NewCanonical(
                            Integer::Cast(value).AsDoubleValue())),
-                       kUnboxedDouble);
+                       representation);
   }
 
   return GetConstant(value, representation);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 6355ea9..b0a50c6 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -395,6 +395,9 @@
     case kUnboxedUint32:
       src_kind = CatchEntryMove::SourceKind::kUint32Slot;
       break;
+    case kUnboxedFloat:
+      src_kind = CatchEntryMove::SourceKind::kFloatSlot;
+      break;
     case kUnboxedDouble:
       src_kind = CatchEntryMove::SourceKind::kDoubleSlot;
       break;
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index e7f9172..6be93b4 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -547,7 +547,8 @@
   while (true) {
     Definition* orig;
     if (def->IsConstraint() || def->IsBox() || def->IsUnbox() ||
-        def->IsIntConverter()) {
+        def->IsIntConverter() || def->IsFloatToDouble() ||
+        def->IsDoubleToFloat()) {
       orig = def->InputAt(0)->definition();
     } else {
       orig = def->OriginalDefinition();
@@ -2131,32 +2132,26 @@
 }
 
 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) {
-#ifdef DEBUG
-  // Must only be used in Float32 StoreIndexedInstr, FloatToDoubleInstr,
-  // Phis introduce by load forwarding, or MaterializeObject for
-  // eliminated Float32 array.
-  ASSERT(env_use_list() == NULL);
-  for (Value* use = input_use_list(); use != NULL; use = use->next_use()) {
-    ASSERT(use->instruction()->IsPhi() ||
-           use->instruction()->IsFloatToDouble() ||
-           (use->instruction()->IsStoreIndexed() &&
-            (use->instruction()->AsStoreIndexed()->class_id() ==
-             kTypedDataFloat32ArrayCid)) ||
-           (use->instruction()->IsMaterializeObject() &&
-            (use->instruction()->AsMaterializeObject()->cls().id() ==
-             kTypedDataFloat32ArrayCid)));
-  }
-#endif
   if (!HasUses()) return NULL;
   if (value()->definition()->IsFloatToDouble()) {
     // F2D(D2F(v)) == v.
     return value()->definition()->AsFloatToDouble()->value()->definition();
   }
+  if (value()->BindsToConstant()) {
+    double narrowed_val =
+        static_cast<float>(Double::Cast(value()->BoundConstant()).value());
+    return flow_graph->GetConstant(
+        Double::ZoneHandle(Double::NewCanonical(narrowed_val)), kUnboxedFloat);
+  }
   return this;
 }
 
 Definition* FloatToDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
-  return HasUses() ? this : NULL;
+  if (!HasUses()) return NULL;
+  if (value()->BindsToConstant()) {
+    return flow_graph->GetConstant(value()->BoundConstant(), kUnboxedDouble);
+  }
+  return this;
 }
 
 Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraph* flow_graph) {
@@ -2176,11 +2171,11 @@
 
   if ((op_kind() == Token::kMUL) &&
       (left()->definition() == right()->definition())) {
-    MathUnaryInstr* math_unary = new MathUnaryInstr(
-        MathUnaryInstr::kDoubleSquare, new Value(left()->definition()),
-        DeoptimizationTarget());
-    flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue);
-    return math_unary;
+    UnaryDoubleOpInstr* square = new UnaryDoubleOpInstr(
+        Token::kSQUARE, new Value(left()->definition()), DeoptimizationTarget(),
+        speculative_mode_, representation());
+    flow_graph->InsertBefore(this, square, env(), FlowGraph::kValue);
+    return square;
   }
 
   return this;
@@ -2621,13 +2616,6 @@
   return HasUses() ? this : NULL;
 }
 
-// A math unary instruction has a side effect (exception
-// thrown) if the argument is not a number.
-// TODO(srdjan): eliminate if has no uses and input is guaranteed to be number.
-Definition* MathUnaryInstr::Canonicalize(FlowGraph* flow_graph) {
-  return this;
-}
-
 bool LoadFieldInstr::TryEvaluateLoad(const Object& instance,
                                      const Slot& field,
                                      Object* result) {
@@ -2992,12 +2980,30 @@
   if ((unbox_defn != NULL) &&
       (unbox_defn->representation() == from_representation()) &&
       (unbox_defn->value()->Type()->ToCid() == Type()->ToCid())) {
+    if (from_representation() == kUnboxedFloat) {
+      // This is a narrowing conversion.
+      return this;
+    }
     return unbox_defn->value()->definition();
   }
 
   return this;
 }
 
+Definition* BoxLanesInstr::Canonicalize(FlowGraph* flow_graph) {
+  return HasUses() ? this : NULL;
+}
+
+Definition* UnboxLaneInstr::Canonicalize(FlowGraph* flow_graph) {
+  if (!HasUses()) return NULL;
+
+  if (BoxLanesInstr* box = value()->definition()->AsBoxLanes()) {
+    return box->InputAt(lane())->definition();
+  }
+
+  return this;
+}
+
 bool BoxIntegerInstr::ValueFitsSmi() const {
   Range* range = value()->definition()->range();
   return RangeUtils::Fits(range, RangeBoundary::kRangeBoundarySmi);
@@ -3054,11 +3060,28 @@
 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) {
   if (!HasUses() && !CanDeoptimize()) return NULL;
 
-  // Fold away Unbox<rep>(Box<rep>(v)).
   BoxInstr* box_defn = value()->definition()->AsBox();
-  if ((box_defn != NULL) &&
-      (box_defn->from_representation() == representation())) {
-    return box_defn->value()->definition();
+  if (box_defn != NULL) {
+    // Fold away Unbox<rep>(Box<rep>(v)).
+    if (box_defn->from_representation() == representation()) {
+      return box_defn->value()->definition();
+    }
+
+    if ((box_defn->from_representation() == kUnboxedDouble) &&
+        (representation() == kUnboxedFloat)) {
+      Definition* replacement = new DoubleToFloatInstr(
+          box_defn->value()->CopyWithType(), DeoptId::kNone);
+      flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue);
+      return replacement;
+    }
+
+    if ((box_defn->from_representation() == kUnboxedFloat) &&
+        (representation() == kUnboxedDouble)) {
+      Definition* replacement = new FloatToDoubleInstr(
+          box_defn->value()->CopyWithType(), DeoptId::kNone);
+      flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue);
+      return replacement;
+    }
   }
 
   if (representation() == kUnboxedDouble && value()->BindsToConstant()) {
@@ -3073,6 +3096,22 @@
     }
   }
 
+  if (representation() == kUnboxedFloat && value()->BindsToConstant()) {
+    const Object& val = value()->BoundConstant();
+    if (val.IsInteger()) {
+      double narrowed_val =
+          static_cast<float>(Integer::Cast(val).AsDoubleValue());
+      return flow_graph->GetConstant(
+          Double::ZoneHandle(Double::NewCanonical(narrowed_val)),
+          kUnboxedFloat);
+    } else if (val.IsDouble()) {
+      double narrowed_val = static_cast<float>(Double::Cast(val).value());
+      return flow_graph->GetConstant(
+          Double::ZoneHandle(Double::NewCanonical(narrowed_val)),
+          kUnboxedFloat);
+    }
+  }
+
   return this;
 }
 
@@ -6431,19 +6470,6 @@
   return kLibcPowRuntimeEntry;
 }
 
-const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) {
-  switch (kind) {
-    case kIllegal:
-      return "illegal";
-    case kSqrt:
-      return "sqrt";
-    case kDoubleSquare:
-      return "double-square";
-  }
-  UNREACHABLE();
-  return "";
-}
-
 TruncDivModInstr::TruncDivModInstr(Value* lhs, Value* rhs, intptr_t deopt_id)
     : TemplateDefinition(deopt_id) {
   SetInputAt(0, lhs);
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index af9f8b1..d4df4c7 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -451,6 +451,8 @@
   M(LoadStaticField, _)                                                        \
   M(StoreStaticField, kNoGC)                                                   \
   M(BooleanNegate, kNoGC)                                                      \
+  M(BoolToInt, kNoGC)                                                          \
+  M(IntToBool, kNoGC)                                                          \
   M(InstanceOf, _)                                                             \
   M(CreateArray, _)                                                            \
   M(AllocateObject, _)                                                         \
@@ -474,9 +476,9 @@
   M(Int64ToDouble, kNoGC)                                                      \
   M(DoubleToInteger, _)                                                        \
   M(DoubleToSmi, kNoGC)                                                        \
-  M(DoubleToDouble, kNoGC)                                                     \
   M(DoubleToFloat, kNoGC)                                                      \
   M(FloatToDouble, kNoGC)                                                      \
+  M(FloatCompare, kNoGC)                                                       \
   M(CheckClass, kNoGC)                                                         \
   M(CheckClassId, kNoGC)                                                       \
   M(CheckSmi, kNoGC)                                                           \
@@ -487,7 +489,6 @@
   M(CheckEitherNonSmi, kNoGC)                                                  \
   M(BinaryDoubleOp, kNoGC)                                                     \
   M(DoubleTestOp, kNoGC)                                                       \
-  M(MathUnary, kNoGC)                                                          \
   M(MathMinMax, kNoGC)                                                         \
   M(Box, _)                                                                    \
   M(Unbox, kNoGC)                                                              \
@@ -515,6 +516,8 @@
   M(TestSmi, kNoGC)                                                            \
   M(TestCids, kNoGC)                                                           \
   M(ExtractNthOutput, kNoGC)                                                   \
+  M(UnboxLane, kNoGC)                                                          \
+  M(BoxLanes, _)                                                               \
   M(BinaryUint32Op, kNoGC)                                                     \
   M(ShiftUint32Op, kNoGC)                                                      \
   M(SpeculativeShiftUint32Op, kNoGC)                                           \
@@ -6251,6 +6254,58 @@
   DISALLOW_COPY_AND_ASSIGN(BooleanNegateInstr);
 };
 
+// bool ? -1 : 0
+class BoolToIntInstr : public TemplateDefinition<1, NoThrow> {
+ public:
+  explicit BoolToIntInstr(Value* value) {
+    ASSERT(value->definition()->representation() == kTagged);
+    SetInputAt(0, value);
+  }
+
+  DECLARE_INSTRUCTION(BoolToInt)
+  virtual CompileType ComputeType() const;
+
+  Value* value() const { return inputs_[0]; }
+
+  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    return kTagged;
+  }
+  virtual Representation representation() const { return kUnboxedInt32; }
+
+  virtual bool ComputeCanDeoptimize() const { return false; }
+
+  virtual bool HasUnknownSideEffects() const { return false; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BoolToIntInstr);
+};
+
+// int == 0 ? false : true
+class IntToBoolInstr : public TemplateDefinition<1, NoThrow> {
+ public:
+  explicit IntToBoolInstr(Value* value) {
+    ASSERT(value->definition()->representation() == kUnboxedInt32);
+    SetInputAt(0, value);
+  }
+
+  DECLARE_INSTRUCTION(IntToBool)
+  virtual CompileType ComputeType() const;
+
+  Value* value() const { return inputs_[0]; }
+
+  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    return kUnboxedInt32;
+  }
+  virtual Representation representation() const { return kTagged; }
+
+  virtual bool ComputeCanDeoptimize() const { return false; }
+
+  virtual bool HasUnknownSideEffects() const { return false; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IntToBoolInstr);
+};
+
 class InstanceOfInstr : public TemplateDefinition<3, Throws> {
  public:
   InstanceOfInstr(const InstructionSource& source,
@@ -7490,60 +7545,6 @@
          IsBoxInt64() || IsUnboxInt64();
 }
 
-class MathUnaryInstr : public TemplateDefinition<1, NoThrow, Pure> {
- public:
-  enum MathUnaryKind {
-    kIllegal,
-    kSqrt,
-    kDoubleSquare,
-  };
-  MathUnaryInstr(MathUnaryKind kind, Value* value, intptr_t deopt_id)
-      : TemplateDefinition(deopt_id), kind_(kind) {
-    SetInputAt(0, value);
-  }
-
-  Value* value() const { return inputs_[0]; }
-  MathUnaryKind kind() const { return kind_; }
-
-  virtual bool ComputeCanDeoptimize() const { return false; }
-
-  virtual Representation representation() const { return kUnboxedDouble; }
-
-  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
-    ASSERT(idx == 0);
-    return kUnboxedDouble;
-  }
-
-  virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
-    ASSERT(idx == 0);
-    return kNotSpeculative;
-  }
-
-  virtual intptr_t DeoptimizationTarget() const {
-    // Direct access since this instruction cannot deoptimize, and the deopt-id
-    // was inherited from another instruction that could deoptimize.
-    return GetDeoptId();
-  }
-
-  DECLARE_INSTRUCTION(MathUnary)
-  virtual CompileType ComputeType() const;
-
-  virtual bool AttributesEqual(const Instruction& other) const {
-    return kind() == other.AsMathUnary()->kind();
-  }
-
-  Definition* Canonicalize(FlowGraph* flow_graph);
-
-  static const char* KindToCString(MathUnaryKind kind);
-
-  PRINT_OPERANDS_TO_SUPPORT
-
- private:
-  const MathUnaryKind kind_;
-
-  DISALLOW_COPY_AND_ASSIGN(MathUnaryInstr);
-};
-
 // Calls into the runtime and performs a case-insensitive comparison of the
 // UTF16 strings (i.e. TwoByteString or ExternalTwoByteString) located at
 // str[lhs_index:lhs_index + length] and str[rhs_index:rhs_index + length].
@@ -7663,11 +7664,15 @@
                       Value* right,
                       intptr_t deopt_id,
                       const InstructionSource& source,
-                      SpeculativeMode speculative_mode = kGuardInputs)
+                      SpeculativeMode speculative_mode = kGuardInputs,
+                      Representation representation = kUnboxedDouble)
       : TemplateDefinition(source, deopt_id),
         op_kind_(op_kind),
         token_pos_(source.token_pos),
-        speculative_mode_(speculative_mode) {
+        speculative_mode_(speculative_mode),
+        representation_(representation) {
+    ASSERT((representation == kUnboxedFloat) ||
+           (representation == kUnboxedDouble));
     SetInputAt(0, left);
     SetInputAt(1, right);
   }
@@ -7681,11 +7686,11 @@
 
   virtual bool ComputeCanDeoptimize() const { return false; }
 
-  virtual Representation representation() const { return kUnboxedDouble; }
+  virtual Representation representation() const { return representation_; }
 
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
     ASSERT((idx == 0) || (idx == 1));
-    return kUnboxedDouble;
+    return representation_;
   }
 
   virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
@@ -7708,13 +7713,15 @@
   virtual bool AttributesEqual(const Instruction& other) const {
     auto const other_bin_op = other.AsBinaryDoubleOp();
     return (op_kind() == other_bin_op->op_kind()) &&
-           (speculative_mode_ == other_bin_op->speculative_mode_);
+           (speculative_mode_ == other_bin_op->speculative_mode_) &&
+           (representation_ == other_bin_op->representation_);
   }
 
  private:
   const Token::Kind op_kind_;
   const TokenPosition token_pos_;
   const SpeculativeMode speculative_mode_;
+  const Representation representation_;
 
   DISALLOW_COPY_AND_ASSIGN(BinaryDoubleOpInstr);
 };
@@ -8297,17 +8304,19 @@
   DISALLOW_COPY_AND_ASSIGN(SpeculativeShiftUint32OpInstr);
 };
 
-// Handles only NEGATE.
 class UnaryDoubleOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
  public:
   UnaryDoubleOpInstr(Token::Kind op_kind,
                      Value* value,
                      intptr_t deopt_id,
-                     SpeculativeMode speculative_mode = kGuardInputs)
+                     SpeculativeMode speculative_mode = kGuardInputs,
+                     Representation representation = kUnboxedDouble)
       : TemplateDefinition(deopt_id),
         op_kind_(op_kind),
-        speculative_mode_(speculative_mode) {
-    ASSERT(op_kind == Token::kNEGATE);
+        speculative_mode_(speculative_mode),
+        representation_(representation) {
+    ASSERT((representation == kUnboxedFloat) ||
+           (representation == kUnboxedDouble));
     SetInputAt(0, value);
   }
 
@@ -8325,11 +8334,11 @@
     return GetDeoptId();
   }
 
-  virtual Representation representation() const { return kUnboxedDouble; }
+  virtual Representation representation() const { return representation_; }
 
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
     ASSERT(idx == 0);
-    return kUnboxedDouble;
+    return representation_;
   }
 
   virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
@@ -8337,7 +8346,8 @@
   }
 
   virtual bool AttributesEqual(const Instruction& other) const {
-    return speculative_mode_ == other.AsUnaryDoubleOp()->speculative_mode_;
+    return (speculative_mode_ == other.AsUnaryDoubleOp()->speculative_mode_) &&
+           (representation_ == other.AsUnaryDoubleOp()->representation_);
   }
 
   PRINT_OPERANDS_TO_SUPPORT
@@ -8345,6 +8355,7 @@
  private:
   const Token::Kind op_kind_;
   const SpeculativeMode speculative_mode_;
+  const Representation representation_;
 
   DISALLOW_COPY_AND_ASSIGN(UnaryDoubleOpInstr);
 };
@@ -8574,51 +8585,6 @@
   DISALLOW_COPY_AND_ASSIGN(DoubleToSmiInstr);
 };
 
-class DoubleToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
- public:
-  DoubleToDoubleInstr(Value* value,
-                      MethodRecognizer::Kind recognized_kind,
-                      intptr_t deopt_id)
-      : TemplateDefinition(deopt_id), recognized_kind_(recognized_kind) {
-    ASSERT((recognized_kind == MethodRecognizer::kDoubleTruncateToDouble) ||
-           (recognized_kind == MethodRecognizer::kDoubleFloorToDouble) ||
-           (recognized_kind == MethodRecognizer::kDoubleCeilToDouble));
-    SetInputAt(0, value);
-  }
-
-  Value* value() const { return inputs_[0]; }
-
-  MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
-
-  DECLARE_INSTRUCTION(DoubleToDouble)
-  virtual CompileType ComputeType() const;
-
-  virtual bool ComputeCanDeoptimize() const { return false; }
-
-  virtual Representation representation() const { return kUnboxedDouble; }
-
-  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
-    ASSERT(idx == 0);
-    return kUnboxedDouble;
-  }
-
-  virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
-    ASSERT(idx == 0);
-    return kNotSpeculative;
-  }
-
-  virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
-
-  virtual bool AttributesEqual(const Instruction& other) const {
-    return other.AsDoubleToDouble()->recognized_kind() == recognized_kind();
-  }
-
- private:
-  const MethodRecognizer::Kind recognized_kind_;
-
-  DISALLOW_COPY_AND_ASSIGN(DoubleToDoubleInstr);
-};
-
 class DoubleToFloatInstr : public TemplateDefinition<1, NoThrow, Pure> {
  public:
   DoubleToFloatInstr(Value* value,
@@ -8691,6 +8657,42 @@
   DISALLOW_COPY_AND_ASSIGN(FloatToDoubleInstr);
 };
 
+// left op right ? -1 : 0
+class FloatCompareInstr : public TemplateDefinition<2, NoThrow, Pure> {
+ public:
+  FloatCompareInstr(Token::Kind op_kind, Value* left, Value* right)
+      : op_kind_(op_kind) {
+    SetInputAt(0, left);
+    SetInputAt(1, right);
+  }
+
+  Value* left() const { return inputs_[0]; }
+  Value* right() const { return inputs_[1]; }
+
+  Token::Kind op_kind() const { return op_kind_; }
+
+  DECLARE_INSTRUCTION(FloatCompare)
+
+  virtual CompileType ComputeType() const;
+
+  virtual bool ComputeCanDeoptimize() const { return false; }
+
+  virtual Representation representation() const { return kUnboxedInt32; }
+
+  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    return kUnboxedFloat;
+  }
+
+  virtual bool AttributesEqual(const Instruction& other) const {
+    return other.AsFloatCompare()->op_kind() == op_kind();
+  }
+
+ private:
+  const Token::Kind op_kind_;
+
+  DISALLOW_COPY_AND_ASSIGN(FloatCompareInstr);
+};
+
 // TODO(sjindel): Replace with FFICallInstr.
 class InvokeMathCFunctionInstr : public PureDefinition {
  public:
@@ -8803,6 +8805,136 @@
   DISALLOW_COPY_AND_ASSIGN(ExtractNthOutputInstr);
 };
 
+class UnboxLaneInstr : public TemplateDefinition<1, NoThrow, Pure> {
+ public:
+  UnboxLaneInstr(Value* value,
+                 intptr_t n,
+                 Representation definition_rep,
+                 intptr_t definition_cid)
+      : lane_(n),
+        definition_rep_(definition_rep),
+        definition_cid_(definition_cid) {
+    SetInputAt(0, value);
+  }
+
+  Value* value() const { return inputs_[0]; }
+
+  DECLARE_INSTRUCTION(UnboxLane)
+
+  virtual CompileType ComputeType() const;
+  virtual bool ComputeCanDeoptimize() const { return false; }
+
+  intptr_t lane() const { return lane_; }
+
+  virtual Representation representation() const { return definition_rep_; }
+
+  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    ASSERT(idx == 0);
+    return kTagged;
+  }
+
+  virtual bool AttributesEqual(const Instruction& other) const {
+    auto const other_split = other.AsUnboxLane();
+    return (other_split->representation() == representation()) &&
+           (other_split->lane() == lane());
+  }
+
+  Definition* Canonicalize(FlowGraph* flow_graph);
+
+  PRINT_OPERANDS_TO_SUPPORT
+
+ private:
+  const intptr_t lane_;
+  const Representation definition_rep_;
+  const intptr_t definition_cid_;
+  DISALLOW_COPY_AND_ASSIGN(UnboxLaneInstr);
+};
+
+class BoxLanesInstr : public TemplateDefinition<4, NoThrow, Pure> {
+ public:
+  BoxLanesInstr(Representation from_representation, Value* x, Value* y)
+      : from_representation_(from_representation) {
+    ASSERT(from_representation == kUnboxedDouble);
+    ASSERT(x->definition()->representation() == from_representation);
+    ASSERT(y->definition()->representation() == from_representation);
+    SetInputAt(0, x);
+    SetInputAt(1, y);
+  }
+  BoxLanesInstr(Representation from_representation,
+                Value* x,
+                Value* y,
+                Value* z,
+                Value* w)
+      : from_representation_(from_representation) {
+    ASSERT((from_representation == kUnboxedInt32) ||
+           (from_representation == kUnboxedFloat));
+    ASSERT(x->definition()->representation() == from_representation);
+    ASSERT(y->definition()->representation() == from_representation);
+    ASSERT(z->definition()->representation() == from_representation);
+    ASSERT(w->definition()->representation() == from_representation);
+    SetInputAt(0, x);
+    SetInputAt(1, y);
+    SetInputAt(2, z);
+    SetInputAt(3, w);
+  }
+
+  intptr_t InputCount() const {
+    switch (from_representation_) {
+      case kUnboxedDouble:
+        return 2;
+      case kUnboxedFloat:
+        return 4;
+      case kUnboxedInt32:
+        return 4;
+      default:
+        UNREACHABLE();
+        return 0;
+    }
+  }
+  Value* x() const { return inputs_[0]; }
+  Value* y() const { return inputs_[1]; }
+  Value* z() const {
+    ASSERT((from_representation() == kUnboxedInt32) ||
+           (from_representation() == kUnboxedFloat));
+    return inputs_[2];
+  }
+  Value* w() const {
+    ASSERT((from_representation() == kUnboxedInt32) ||
+           (from_representation() == kUnboxedFloat));
+    return inputs_[3];
+  }
+  Representation from_representation() const { return from_representation_; }
+
+  DECLARE_INSTRUCTION(BoxLanes)
+  virtual CompileType ComputeType() const;
+
+  virtual bool ComputeCanDeoptimize() const { return false; }
+  virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
+
+  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    ASSERT(idx == 0 || idx == 1 || idx == 2 || idx == 3);
+    return from_representation();
+  }
+
+  virtual bool AttributesEqual(const Instruction& other) const {
+    return other.AsBoxLanes()->from_representation() == from_representation();
+  }
+
+  Definition* Canonicalize(FlowGraph* flow_graph);
+
+  virtual TokenPosition token_pos() const { return TokenPosition::kBox; }
+
+  virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
+    return kNotSpeculative;
+  }
+
+  PRINT_OPERANDS_TO_SUPPORT
+
+ private:
+  const Representation from_representation_;
+  DISALLOW_COPY_AND_ASSIGN(BoxLanesInstr);
+};
+
 class TruncDivModInstr : public TemplateDefinition<2, NoThrow, Pure> {
  public:
   TruncDivModInstr(Value* lhs, Value* rhs, intptr_t deopt_id);
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index e4bc74b..0e131fa 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -698,11 +698,10 @@
     }
   } else if (destination.IsFpuRegister()) {
     const DRegister dst = EvenDRegisterOf(destination.fpu_reg());
-    if (Utils::DoublesBitEqual(Double::Cast(value_).value(), 0.0) &&
-        TargetCPUFeatures::neon_supported()) {
-      QRegister qdst = destination.fpu_reg();
-      __ veorq(qdst, qdst, qdst);
+    if (representation() == kUnboxedFloat) {
+      __ LoadSImmediate(EvenSRegisterOf(dst), Double::Cast(value_).value());
     } else {
+      ASSERT(representation() == kUnboxedDouble);
       ASSERT(tmp != kNoRegister);
       __ LoadDImmediate(dst, Double::Cast(value_).value(), tmp);
     }
@@ -5704,33 +5703,6 @@
 
 #undef DEFINE_EMIT
 
-LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
-                                                     bool opt) const {
-  ASSERT((kind() == MathUnaryInstr::kSqrt) ||
-         (kind() == MathUnaryInstr::kDoubleSquare));
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresFpuRegister());
-  summary->set_out(0, Location::RequiresFpuRegister());
-  return summary;
-}
-
-void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (kind() == MathUnaryInstr::kSqrt) {
-    const DRegister val = EvenDRegisterOf(locs()->in(0).fpu_reg());
-    const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
-    __ vsqrtd(result, val);
-  } else if (kind() == MathUnaryInstr::kDoubleSquare) {
-    const DRegister val = EvenDRegisterOf(locs()->in(0).fpu_reg());
-    const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
-    __ vmuld(result, val, val);
-  } else {
-    UNREACHABLE();
-  }
-}
-
 LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
     Zone* zone,
     bool opt) const {
@@ -5883,9 +5855,22 @@
 }
 
 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ASSERT(representation() == kUnboxedDouble);
   const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
   const DRegister value = EvenDRegisterOf(locs()->in(0).fpu_reg());
-  __ vnegd(result, value);
+  switch (op_kind()) {
+    case Token::kNEGATE:
+      __ vnegd(result, value);
+      break;
+    case Token::kSQRT:
+      __ vsqrtd(result, value);
+      break;
+    case Token::kSQUARE:
+      __ vmuld(result, value, value);
+      break;
+    default:
+      UNREACHABLE();
+  }
 }
 
 LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -6000,16 +5985,6 @@
   __ SmiTag(result);
 }
 
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
-                                                          bool opt) const {
-  UNIMPLEMENTED();
-  return NULL;
-}
-
-void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
-}
-
 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
                                                          bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -6048,6 +6023,16 @@
   __ vcvtds(result, value);
 }
 
+LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
+                                                        bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(Zone* zone,
                                                                bool opt) const {
   ASSERT((InputCount() == 1) || (InputCount() == 2));
@@ -6298,6 +6283,26 @@
   }
 }
 
+LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
+                                                    bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -7577,6 +7582,26 @@
          compiler::Operand(compiler::target::ObjectAlignment::kBoolValueMask));
 }
 
+LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,
                                                           bool opt) const {
   const intptr_t kNumInputs = (type_arguments() != nullptr) ? 1 : 0;
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index ca277fb..e61557a 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -625,6 +625,12 @@
   } else if (destination.IsFpuRegister()) {
     const VRegister dst = destination.fpu_reg();
     __ LoadDImmediate(dst, Double::Cast(value_).value());
+    if (representation() == kUnboxedFloat) {
+      __ LoadSImmediate(dst, Double::Cast(value_).value());
+    } else {
+      ASSERT(representation() == kUnboxedDouble);
+      __ LoadDImmediate(dst, Double::Cast(value_).value());
+    }
   } else if (destination.IsDoubleStackSlot()) {
     const intptr_t dest_offset = destination.ToStackSlotOffset();
     if (Utils::DoublesBitEqual(Double::Cast(value_).value(), 0.0)) {
@@ -4796,33 +4802,6 @@
 
 #undef DEFINE_EMIT
 
-LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
-                                                     bool opt) const {
-  ASSERT((kind() == MathUnaryInstr::kSqrt) ||
-         (kind() == MathUnaryInstr::kDoubleSquare));
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresFpuRegister());
-  summary->set_out(0, Location::RequiresFpuRegister());
-  return summary;
-}
-
-void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (kind() == MathUnaryInstr::kSqrt) {
-    const VRegister val = locs()->in(0).fpu_reg();
-    const VRegister result = locs()->out(0).fpu_reg();
-    __ fsqrtd(result, val);
-  } else if (kind() == MathUnaryInstr::kDoubleSquare) {
-    const VRegister val = locs()->in(0).fpu_reg();
-    const VRegister result = locs()->out(0).fpu_reg();
-    __ fmuld(result, val, val);
-  } else {
-    UNREACHABLE();
-  }
-}
-
 LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
     Zone* zone,
     bool opt) const {
@@ -4975,9 +4954,22 @@
 }
 
 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ASSERT(representation() == kUnboxedDouble);
   const VRegister result = locs()->out(0).fpu_reg();
   const VRegister value = locs()->in(0).fpu_reg();
-  __ fnegd(result, value);
+  switch (op_kind()) {
+    case Token::kNEGATE:
+      __ fnegd(result, value);
+      break;
+    case Token::kSQRT:
+      __ fsqrtd(result, value);
+      break;
+    case Token::kSQUARE:
+      __ fmuld(result, value, value);
+      break;
+    default:
+      UNREACHABLE();
+  }
 }
 
 LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -5126,16 +5118,6 @@
   __ SmiTag(result);
 }
 
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
-                                                          bool opt) const {
-  UNIMPLEMENTED();
-  return NULL;
-}
-
-void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
-}
-
 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
                                                          bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -5170,6 +5152,16 @@
   __ fcvtds(result, value);
 }
 
+LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
+                                                        bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(Zone* zone,
                                                                bool opt) const {
   ASSERT((InputCount() == 1) || (InputCount() == 2));
@@ -5372,6 +5364,26 @@
   }
 }
 
+LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
+                                                    bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -6675,6 +6687,26 @@
       compiler::Immediate(compiler::target::ObjectAlignment::kBoolValueMask));
 }
 
+LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,
                                                           bool opt) const {
   const intptr_t kNumInputs = (type_arguments() != nullptr) ? 1 : 0;
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index b84f33e..4d24aa2 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -421,18 +421,23 @@
       __ LoadObjectSafely(destination.reg(), value_);
     }
   } else if (destination.IsFpuRegister()) {
-    const double value_as_double = Double::Cast(value_).value();
-    uword addr = FindDoubleConstant(value_as_double);
-    if (addr == 0) {
-      __ pushl(EAX);
-      __ LoadObject(EAX, value_);
-      __ movsd(destination.fpu_reg(),
-               compiler::FieldAddress(EAX, Double::value_offset()));
-      __ popl(EAX);
-    } else if (Utils::DoublesBitEqual(value_as_double, 0.0)) {
-      __ xorps(destination.fpu_reg(), destination.fpu_reg());
+    if (representation() == kUnboxedFloat) {
+      __ LoadSImmediate(destination.fpu_reg(),
+                        static_cast<float>(Double::Cast(value_).value()));
     } else {
-      __ movsd(destination.fpu_reg(), compiler::Address::Absolute(addr));
+      const double value_as_double = Double::Cast(value_).value();
+      uword addr = FindDoubleConstant(value_as_double);
+      if (addr == 0) {
+        __ pushl(EAX);
+        __ LoadObject(EAX, value_);
+        __ movsd(destination.fpu_reg(),
+                 compiler::FieldAddress(EAX, Double::value_offset()));
+        __ popl(EAX);
+      } else if (Utils::DoublesBitEqual(value_as_double, 0.0)) {
+        __ xorps(destination.fpu_reg(), destination.fpu_reg());
+      } else {
+        __ movsd(destination.fpu_reg(), compiler::Address::Absolute(addr));
+      }
     }
   } else if (destination.IsDoubleStackSlot()) {
     const double value_as_double = Double::Cast(value_).value();
@@ -4817,35 +4822,6 @@
 
 #undef DEFINE_EMIT
 
-LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
-                                                     bool opt) const {
-  ASSERT((kind() == MathUnaryInstr::kSqrt) ||
-         (kind() == MathUnaryInstr::kDoubleSquare));
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresFpuRegister());
-  if (kind() == MathUnaryInstr::kDoubleSquare) {
-    summary->set_out(0, Location::SameAsFirstInput());
-  } else {
-    summary->set_out(0, Location::RequiresFpuRegister());
-  }
-  return summary;
-}
-
-void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (kind() == MathUnaryInstr::kSqrt) {
-    __ sqrtsd(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
-  } else if (kind() == MathUnaryInstr::kDoubleSquare) {
-    XmmRegister value_reg = locs()->in(0).fpu_reg();
-    __ mulsd(value_reg, value_reg);
-    ASSERT(value_reg == locs()->out(0).fpu_reg());
-  } else {
-    UNREACHABLE();
-  }
-}
-
 LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
     Zone* zone,
     bool opt) const {
@@ -5001,9 +4977,31 @@
 }
 
 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ASSERT(representation() == kUnboxedDouble);
   XmmRegister value = locs()->in(0).fpu_reg();
   ASSERT(locs()->out(0).fpu_reg() == value);
-  __ DoubleNegate(value);
+  switch (op_kind()) {
+    case Token::kNEGATE:
+      __ DoubleNegate(value);
+      break;
+    case Token::kSQRT:
+      __ sqrtsd(value, value);
+      break;
+    case Token::kSQUARE:
+      __ mulsd(value, value);
+      break;
+    case Token::kTRUNCATE:
+      __ roundsd(value, value, compiler::Assembler::kRoundToZero);
+      break;
+    case Token::kFLOOR:
+      __ roundsd(value, value, compiler::Assembler::kRoundDown);
+      break;
+    case Token::kCEILING:
+      __ roundsd(value, value, compiler::Assembler::kRoundUp);
+      break;
+    default:
+      UNREACHABLE();
+  }
 }
 
 LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -5126,35 +5124,6 @@
   __ SmiTag(result);
 }
 
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
-                                                          bool opt) const {
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* result = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  result->set_in(0, Location::RequiresFpuRegister());
-  result->set_out(0, Location::RequiresFpuRegister());
-  return result;
-}
-
-void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  XmmRegister value = locs()->in(0).fpu_reg();
-  XmmRegister result = locs()->out(0).fpu_reg();
-  switch (recognized_kind()) {
-    case MethodRecognizer::kDoubleTruncateToDouble:
-      __ roundsd(result, value, compiler::Assembler::kRoundToZero);
-      break;
-    case MethodRecognizer::kDoubleFloorToDouble:
-      __ roundsd(result, value, compiler::Assembler::kRoundDown);
-      break;
-    case MethodRecognizer::kDoubleCeilToDouble:
-      __ roundsd(result, value, compiler::Assembler::kRoundUp);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
                                                          bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -5185,6 +5154,16 @@
   __ cvtss2sd(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
 }
 
+LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
+                                                        bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(Zone* zone,
                                                                bool opt) const {
   ASSERT((InputCount() == 1) || (InputCount() == 2));
@@ -5411,6 +5390,26 @@
   }
 }
 
+LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
+                                                    bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -6662,6 +6661,26 @@
                       compiler::target::ObjectAlignment::kBoolValueMask));
 }
 
+LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,
                                                           bool opt) const {
   const intptr_t kNumInputs = (type_arguments() != nullptr) ? 1 : 0;
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 05b7050..da9c0c9 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -484,7 +484,9 @@
     range_->PrintTo(f);
   }
 
-  if (type_ != NULL) {
+  if (representation() != kNoRepresentation && representation() != kTagged) {
+    f->Printf(" %s", RepresentationToCString(representation()));
+  } else if (type_ != NULL) {
     f->AddString(" ");
     type_->PrintTo(f);
   }
@@ -553,10 +555,6 @@
     buffer[pos] = '\0';
     f->Printf("#%s\\n...", buffer);
   }
-
-  if (representation() != kNoRepresentation && representation() != kTagged) {
-    f->Printf(" %s", RepresentationToCString(representation()));
-  }
 }
 
 void ConstraintInstr::PrintOperandsTo(BaseTextBuffer* f) const {
@@ -910,11 +908,6 @@
   TemplateAllocation::PrintOperandsTo(f);
 }
 
-void MathUnaryInstr::PrintOperandsTo(BaseTextBuffer* f) const {
-  f->Printf("'%s', ", MathUnaryInstr::KindToCString(kind()));
-  value()->PrintTo(f);
-}
-
 void TruncDivModInstr::PrintOperandsTo(BaseTextBuffer* f) const {
   Definition::PrintOperandsTo(f);
 }
@@ -924,6 +917,15 @@
   Definition::PrintOperandsTo(f);
 }
 
+void UnboxLaneInstr::PrintOperandsTo(BaseTextBuffer* f) const {
+  Definition::PrintOperandsTo(f);
+  f->Printf(", lane %" Pd, lane());
+}
+
+void BoxLanesInstr::PrintOperandsTo(BaseTextBuffer* f) const {
+  Definition::PrintOperandsTo(f);
+}
+
 void UnaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
   f->Printf("%s, ", Token::Str(op_kind()));
   value()->PrintTo(f);
diff --git a/runtime/vm/compiler/backend/il_riscv.cc b/runtime/vm/compiler/backend/il_riscv.cc
index 041f180..2222f9b 100644
--- a/runtime/vm/compiler/backend/il_riscv.cc
+++ b/runtime/vm/compiler/backend/il_riscv.cc
@@ -715,7 +715,12 @@
     }
   } else if (destination.IsFpuRegister()) {
     const FRegister dst = destination.fpu_reg();
-    __ LoadDImmediate(dst, Double::Cast(value_).value());
+    if (representation() == kUnboxedFloat) {
+      __ LoadSImmediate(dst, Double::Cast(value_).value());
+    } else {
+      ASSERT(representation() == kUnboxedDouble);
+      __ LoadDImmediate(dst, Double::Cast(value_).value());
+    }
   } else if (destination.IsDoubleStackSlot()) {
     const intptr_t dest_offset = destination.ToStackSlotOffset();
 #if XLEN == 32
@@ -1198,7 +1203,7 @@
       __ CompareImmediate(TMP, 0);
       return NE;
     case Token::kGT:
-      __ fltd(TMP, right, left);
+      __ fgtd(TMP, left, right);
       __ CompareImmediate(TMP, 0);
       return NE;
     case Token::kLTE:
@@ -1206,7 +1211,7 @@
       __ CompareImmediate(TMP, 0);
       return NE;
     case Token::kGTE:
-      __ fled(TMP, right, left);
+      __ fged(TMP, left, right);
       __ CompareImmediate(TMP, 0);
       return NE;
     default:
@@ -3363,9 +3368,11 @@
         __ LoadDFieldFromOffset(result, temp, Double::value_offset());
         break;
       case kFloat32x4Cid:
+        __ Comment("UnboxedFloat32x4LoadFieldInstr");
         UNIMPLEMENTED();
         break;
       case kFloat64x2Cid:
+        __ Comment("UnboxedFloat64x2LoadFieldInstr");
         UNIMPLEMENTED();
         break;
       default:
@@ -4434,6 +4441,16 @@
     }
 #endif
 
+    case kUnboxedFloat: {
+      const FRegister result = locs()->out(0).fpu_reg();
+      __ SmiUntag(TMP, box);
+#if XLEN == 32
+      __ fcvtsw(result, TMP);
+#elif XLEN == 64
+      __ fcvtsl(result, TMP);
+#endif
+      break;
+    }
     case kUnboxedDouble: {
       const FRegister result = locs()->out(0).fpu_reg();
       __ SmiUntag(TMP, box);
@@ -4808,21 +4825,53 @@
   const FRegister left = locs()->in(0).fpu_reg();
   const FRegister right = locs()->in(1).fpu_reg();
   const FRegister result = locs()->out(0).fpu_reg();
-  switch (op_kind()) {
-    case Token::kADD:
-      __ faddd(result, left, right);
-      break;
-    case Token::kSUB:
-      __ fsubd(result, left, right);
-      break;
-    case Token::kMUL:
-      __ fmuld(result, left, right);
-      break;
-    case Token::kDIV:
-      __ fdivd(result, left, right);
-      break;
-    default:
-      UNREACHABLE();
+  if (representation() == kUnboxedDouble) {
+    switch (op_kind()) {
+      case Token::kADD:
+        __ faddd(result, left, right);
+        break;
+      case Token::kSUB:
+        __ fsubd(result, left, right);
+        break;
+      case Token::kMUL:
+        __ fmuld(result, left, right);
+        break;
+      case Token::kDIV:
+        __ fdivd(result, left, right);
+        break;
+      case Token::kMIN:
+        __ fmind(result, left, right);
+        break;
+      case Token::kMAX:
+        __ fmaxd(result, left, right);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  } else {
+    ASSERT(representation() == kUnboxedFloat);
+    switch (op_kind()) {
+      case Token::kADD:
+        __ fadds(result, left, right);
+        break;
+      case Token::kSUB:
+        __ fsubs(result, left, right);
+        break;
+      case Token::kMUL:
+        __ fmuls(result, left, right);
+        break;
+      case Token::kDIV:
+        __ fdivs(result, left, right);
+        break;
+      case Token::kMIN:
+        __ fmins(result, left, right);
+        break;
+      case Token::kMAX:
+        __ fmaxs(result, left, right);
+        break;
+      default:
+        UNREACHABLE();
+    }
   }
 }
 
@@ -4853,259 +4902,13 @@
   return kind() == Token::kEQ ? NOT_ZERO : ZERO;
 }
 
-// SIMD
-
-#define DEFINE_EMIT(Name, Args)                                                \
-  static void Emit##Name(FlowGraphCompiler* compiler, SimdOpInstr* instr,      \
-                         PP_APPLY(PP_UNPACK, Args))
-
-#define SIMD_OP_FLOAT_ARITH(V, Name, op)                                       \
-  V(Float32x4##Name, op##s)                                                    \
-  V(Float64x2##Name, op##d)
-
-#define SIMD_OP_SIMPLE_BINARY(V)                                               \
-  SIMD_OP_FLOAT_ARITH(V, Add, vadd)                                            \
-  SIMD_OP_FLOAT_ARITH(V, Sub, vsub)                                            \
-  SIMD_OP_FLOAT_ARITH(V, Mul, vmul)                                            \
-  SIMD_OP_FLOAT_ARITH(V, Div, vdiv)                                            \
-  SIMD_OP_FLOAT_ARITH(V, Min, vmin)                                            \
-  SIMD_OP_FLOAT_ARITH(V, Max, vmax)                                            \
-  V(Int32x4Add, vaddw)                                                         \
-  V(Int32x4Sub, vsubw)                                                         \
-  V(Int32x4BitAnd, vand)                                                       \
-  V(Int32x4BitOr, vorr)                                                        \
-  V(Int32x4BitXor, veor)                                                       \
-  V(Float32x4Equal, vceqs)                                                     \
-  V(Float32x4GreaterThan, vcgts)                                               \
-  V(Float32x4GreaterThanOrEqual, vcges)
-
-DEFINE_EMIT(SimdBinaryOp, (FRegister result, FRegister left, FRegister right)) {
-  UNIMPLEMENTED();
-}
-
-#define SIMD_OP_SIMPLE_UNARY(V)                                                \
-  SIMD_OP_FLOAT_ARITH(V, Sqrt, vsqrt)                                          \
-  SIMD_OP_FLOAT_ARITH(V, Negate, vneg)                                         \
-  SIMD_OP_FLOAT_ARITH(V, Abs, vabs)                                            \
-  V(Float32x4Reciprocal, VRecps)                                               \
-  V(Float32x4ReciprocalSqrt, VRSqrts)
-
-DEFINE_EMIT(SimdUnaryOp, (FRegister result, FRegister value)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Simd32x4GetSignMask,
-            (Register out, FRegister value, Temp<Register> temp)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(
-    Float32x4FromDoubles,
-    (FRegister r, FRegister v0, FRegister v1, FRegister v2, FRegister v3)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(
-    Float32x4Clamp,
-    (FRegister result, FRegister value, FRegister lower, FRegister upper)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(
-    Float64x2Clamp,
-    (FRegister result, FRegister value, FRegister lower, FRegister upper)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Float32x4With,
-            (FRegister result, FRegister replacement, FRegister value)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Simd32x4ToSimd32x4, (SameAsFirstInput, FRegister value)) {
-  // TODO(dartbug.com/30949) these operations are essentially nop and should
-  // not generate any code. They should be removed from the graph before
-  // code generation.
-}
-
-DEFINE_EMIT(SimdZero, (FRegister v)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Float64x2GetSignMask, (Register out, FRegister value)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Float64x2With,
-            (SameAsFirstInput, FRegister left, FRegister right)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(
-    Int32x4FromInts,
-    (FRegister result, Register v0, Register v1, Register v2, Register v3)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Int32x4FromBools,
-            (FRegister result,
-             Register v0,
-             Register v1,
-             Register v2,
-             Register v3,
-             Temp<Register> temp)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Int32x4GetFlag, (Register result, FRegister value)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Int32x4Select,
-            (FRegister out,
-             FRegister mask,
-             FRegister trueValue,
-             FRegister falseValue,
-             Temp<FRegister> temp)) {
-  UNIMPLEMENTED();
-}
-
-DEFINE_EMIT(Int32x4WithFlag,
-            (SameAsFirstInput, FRegister mask, Register flag)) {
-  UNIMPLEMENTED();
-}
-
-// Map SimdOpInstr::Kind-s to corresponding emit functions. Uses the following
-// format:
-//
-//     CASE(OpA) CASE(OpB) ____(Emitter) - Emitter is used to emit OpA and OpB.
-//     SIMPLE(OpA) - Emitter with name OpA is used to emit OpA.
-//
-#define SIMD_OP_VARIANTS(CASE, ____)                                           \
-  SIMD_OP_SIMPLE_BINARY(CASE)                                                  \
-  CASE(Float32x4ShuffleMix)                                                    \
-  CASE(Int32x4ShuffleMix)                                                      \
-  CASE(Float32x4NotEqual)                                                      \
-  CASE(Float32x4LessThan)                                                      \
-  CASE(Float32x4LessThanOrEqual)                                               \
-  CASE(Float32x4Scale)                                                         \
-  CASE(Float64x2FromDoubles)                                                   \
-  CASE(Float64x2Scale)                                                         \
-  ____(SimdBinaryOp)                                                           \
-  SIMD_OP_SIMPLE_UNARY(CASE)                                                   \
-  CASE(Float32x4GetX)                                                          \
-  CASE(Float32x4GetY)                                                          \
-  CASE(Float32x4GetZ)                                                          \
-  CASE(Float32x4GetW)                                                          \
-  CASE(Int32x4Shuffle)                                                         \
-  CASE(Float32x4Shuffle)                                                       \
-  CASE(Float32x4Splat)                                                         \
-  CASE(Float64x2GetX)                                                          \
-  CASE(Float64x2GetY)                                                          \
-  CASE(Float64x2Splat)                                                         \
-  CASE(Float64x2ToFloat32x4)                                                   \
-  CASE(Float32x4ToFloat64x2)                                                   \
-  ____(SimdUnaryOp)                                                            \
-  CASE(Float32x4GetSignMask)                                                   \
-  CASE(Int32x4GetSignMask)                                                     \
-  ____(Simd32x4GetSignMask)                                                    \
-  CASE(Float32x4FromDoubles)                                                   \
-  ____(Float32x4FromDoubles)                                                   \
-  CASE(Float32x4Zero)                                                          \
-  CASE(Float64x2Zero)                                                          \
-  ____(SimdZero)                                                               \
-  CASE(Float32x4Clamp)                                                         \
-  ____(Float32x4Clamp)                                                         \
-  CASE(Float64x2Clamp)                                                         \
-  ____(Float64x2Clamp)                                                         \
-  CASE(Float32x4WithX)                                                         \
-  CASE(Float32x4WithY)                                                         \
-  CASE(Float32x4WithZ)                                                         \
-  CASE(Float32x4WithW)                                                         \
-  ____(Float32x4With)                                                          \
-  CASE(Float32x4ToInt32x4)                                                     \
-  CASE(Int32x4ToFloat32x4)                                                     \
-  ____(Simd32x4ToSimd32x4)                                                     \
-  CASE(Float64x2GetSignMask)                                                   \
-  ____(Float64x2GetSignMask)                                                   \
-  CASE(Float64x2WithX)                                                         \
-  CASE(Float64x2WithY)                                                         \
-  ____(Float64x2With)                                                          \
-  CASE(Int32x4FromInts)                                                        \
-  ____(Int32x4FromInts)                                                        \
-  CASE(Int32x4FromBools)                                                       \
-  ____(Int32x4FromBools)                                                       \
-  CASE(Int32x4GetFlagX)                                                        \
-  CASE(Int32x4GetFlagY)                                                        \
-  CASE(Int32x4GetFlagZ)                                                        \
-  CASE(Int32x4GetFlagW)                                                        \
-  ____(Int32x4GetFlag)                                                         \
-  CASE(Int32x4Select)                                                          \
-  ____(Int32x4Select)                                                          \
-  CASE(Int32x4WithFlagX)                                                       \
-  CASE(Int32x4WithFlagY)                                                       \
-  CASE(Int32x4WithFlagZ)                                                       \
-  CASE(Int32x4WithFlagW)                                                       \
-  ____(Int32x4WithFlag)
-
 LocationSummary* SimdOpInstr::MakeLocationSummary(Zone* zone, bool opt) const {
-  switch (kind()) {
-#define CASE(Name, ...) case k##Name:
-#define EMIT(Name)                                                             \
-  return MakeLocationSummaryFromEmitter(zone, this, &Emit##Name);
-    SIMD_OP_VARIANTS(CASE, EMIT)
-#undef CASE
-#undef EMIT
-    case kIllegalSimdOp:
-      UNREACHABLE();
-      break;
-  }
   UNREACHABLE();
   return NULL;
 }
 
 void SimdOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  switch (kind()) {
-#define CASE(Name, ...) case k##Name:
-#define EMIT(Name)                                                             \
-  InvokeEmitter(compiler, this, &Emit##Name);                                  \
-  break;
-    SIMD_OP_VARIANTS(CASE, EMIT)
-#undef CASE
-#undef EMIT
-    case kIllegalSimdOp:
-      UNREACHABLE();
-      break;
-  }
-}
-
-#undef DEFINE_EMIT
-
-LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
-                                                     bool opt) const {
-  ASSERT((kind() == MathUnaryInstr::kSqrt) ||
-         (kind() == MathUnaryInstr::kDoubleSquare));
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresFpuRegister());
-  summary->set_out(0, Location::RequiresFpuRegister());
-  return summary;
-}
-
-void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (kind() == MathUnaryInstr::kSqrt) {
-    const FRegister val = locs()->in(0).fpu_reg();
-    const FRegister result = locs()->out(0).fpu_reg();
-    __ fsqrtd(result, val);
-  } else if (kind() == MathUnaryInstr::kDoubleSquare) {
-    const FRegister val = locs()->in(0).fpu_reg();
-    const FRegister result = locs()->out(0).fpu_reg();
-    __ fmuld(result, val, val);
-  } else {
-    UNREACHABLE();
-  }
+  UNREACHABLE();
 }
 
 LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
@@ -5249,7 +5052,53 @@
 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   const FRegister result = locs()->out(0).fpu_reg();
   const FRegister value = locs()->in(0).fpu_reg();
-  __ fnegd(result, value);
+  if (representation() == kUnboxedDouble) {
+    switch (op_kind()) {
+      case Token::kABS:
+        __ fabsd(result, value);
+        break;
+      case Token::kNEGATE:
+        __ fnegd(result, value);
+        break;
+      case Token::kSQRT:
+        __ fsqrtd(result, value);
+        break;
+      case Token::kSQUARE:
+        __ fmuld(result, value, value);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  } else {
+    ASSERT(representation() == kUnboxedFloat);
+    switch (op_kind()) {
+      case Token::kABS:
+        __ fabss(result, value);
+        break;
+      case Token::kNEGATE:
+        __ fnegs(result, value);
+        break;
+      case Token::kRECIPROCAL:
+        __ li(TMP, 1);
+        __ fcvtsw(FTMP, TMP);
+        __ fdivs(result, FTMP, value);
+        break;
+      case Token::kRECIPROCAL_SQRT:
+        __ li(TMP, 1);
+        __ fcvtsw(FTMP, TMP);
+        __ fdivs(result, FTMP, value);
+        __ fsqrts(result, result);
+        break;
+      case Token::kSQRT:
+        __ fsqrts(result, value);
+        break;
+      case Token::kSQUARE:
+        __ fmuls(result, value, value);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  }
 }
 
 LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Zone* zone,
@@ -5397,16 +5246,6 @@
   __ bne(TMP, TMP2, deopt);
 }
 
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
-                                                          bool opt) const {
-  UNIMPLEMENTED();
-  return NULL;
-}
-
-void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
-}
-
 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
                                                          bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -5441,6 +5280,45 @@
   __ fcvtds(result, value);
 }
 
+LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
+                                                        bool opt) const {
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* result = new (zone)
+      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  result->set_in(0, Location::RequiresFpuRegister());
+  result->set_in(1, Location::RequiresFpuRegister());
+  result->set_out(0, Location::RequiresRegister());
+  return result;
+}
+
+void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const FRegister lhs = locs()->in(0).fpu_reg();
+  const FRegister rhs = locs()->in(1).fpu_reg();
+  const Register result = locs()->out(0).reg();
+
+  switch (op_kind()) {
+    case Token::kEQ:
+      __ feqs(result, lhs, rhs);  // lhs op rhs ? 1 : 0
+      break;
+    case Token::kLT:
+      __ flts(result, lhs, rhs);
+      break;
+    case Token::kLTE:
+      __ fles(result, lhs, rhs);
+      break;
+    case Token::kGT:
+      __ fgts(result, lhs, rhs);
+      break;
+    case Token::kGTE:
+      __ fges(result, lhs, rhs);
+      break;
+    default:
+      UNREACHABLE();
+  }
+  __ neg(result, result);  // lhs op rhs ? -1 : 0
+}
+
 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(Zone* zone,
                                                                bool opt) const {
   ASSERT((InputCount() == 1) || (InputCount() == 2));
@@ -5522,6 +5400,119 @@
   }
 }
 
+LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  const intptr_t kNumInputs = 1;
+  LocationSummary* summary =
+      new (zone) LocationSummary(zone, kNumInputs, 0, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  switch (representation()) {
+    case kUnboxedDouble:
+    case kUnboxedFloat:
+      summary->set_out(0, Location::RequiresFpuRegister());
+      break;
+    case kUnboxedInt32:
+      summary->set_out(0, Location::RequiresRegister());
+      break;
+    default:
+      UNREACHABLE();
+  }
+  return summary;
+}
+
+void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register in = locs()->in(0).reg();
+  switch (representation()) {
+    case kUnboxedDouble:
+      __ fld(locs()->out(0).fpu_reg(),
+             compiler::FieldAddress(
+                 in, compiler::target::Float64x2::value_offset() +
+                         lane() * sizeof(double)));
+      break;
+    case kUnboxedFloat:
+      __ flw(locs()->out(0).fpu_reg(),
+             compiler::FieldAddress(
+                 in, compiler::target::Float32x4::value_offset() +
+                         lane() * sizeof(float)));
+      break;
+    case kUnboxedInt32:
+      __ lw(
+          locs()->out(0).reg(),
+          compiler::FieldAddress(in, compiler::target::Int32x4::value_offset() +
+                                         lane() * sizeof(int32_t)));
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
+                                                    bool opt) const {
+  const intptr_t kNumInputs = InputCount();
+  LocationSummary* summary = new (zone)
+      LocationSummary(zone, kNumInputs, 0, LocationSummary::kCallOnSlowPath);
+  switch (from_representation()) {
+    case kUnboxedDouble:
+      summary->set_in(0, Location::RequiresFpuRegister());
+      summary->set_in(1, Location::RequiresFpuRegister());
+      break;
+    case kUnboxedFloat:
+      summary->set_in(0, Location::RequiresFpuRegister());
+      summary->set_in(1, Location::RequiresFpuRegister());
+      summary->set_in(2, Location::RequiresFpuRegister());
+      summary->set_in(3, Location::RequiresFpuRegister());
+      break;
+    case kUnboxedInt32:
+      summary->set_in(0, Location::RequiresRegister());
+      summary->set_in(1, Location::RequiresRegister());
+      summary->set_in(2, Location::RequiresRegister());
+      summary->set_in(3, Location::RequiresRegister());
+      break;
+    default:
+      UNREACHABLE();
+  }
+  summary->set_out(0, Location::RequiresRegister());
+  return summary;
+}
+
+void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register result = locs()->out(0).reg();
+  switch (from_representation()) {
+    case kUnboxedDouble:
+      BoxAllocationSlowPath::Allocate(compiler, this,
+                                      compiler->float64x2_class(), result, TMP);
+      for (intptr_t i = 0; i < 2; i++) {
+        __ fsd(locs()->in(i).fpu_reg(),
+               compiler::FieldAddress(
+                   result, compiler::target::Float64x2::value_offset() +
+                               i * sizeof(double)));
+      }
+      break;
+    case kUnboxedFloat:
+      BoxAllocationSlowPath::Allocate(compiler, this,
+                                      compiler->float32x4_class(), result, TMP);
+      for (intptr_t i = 0; i < 4; i++) {
+        __ fsw(locs()->in(i).fpu_reg(),
+               compiler::FieldAddress(
+                   result, compiler::target::Float32x4::value_offset() +
+                               i * sizeof(float)));
+      }
+      break;
+    case kUnboxedInt32:
+      BoxAllocationSlowPath::Allocate(compiler, this, compiler->int32x4_class(),
+                                      result, TMP);
+      for (intptr_t i = 0; i < 4; i++) {
+        __ sw(locs()->in(i).reg(),
+              compiler::FieldAddress(result,
+                                     compiler::target::Int32x4::value_offset() +
+                                         i * sizeof(int32_t)));
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
 LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -7615,6 +7606,36 @@
   __ xori(result, input, compiler::target::ObjectAlignment::kBoolValueMask);
 }
 
+LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  return LocationSummary::Make(zone, 1, Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
+}
+
+void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register input = locs()->in(0).reg();
+  const Register result = locs()->out(0).reg();
+  __ LoadObject(TMP, Bool::True());
+  __ xor_(TMP, TMP, input);
+  __ seqz(TMP, TMP);
+  __ neg(result, TMP);
+}
+
+LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  return LocationSummary::Make(zone, 1, Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
+}
+
+void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register input = locs()->in(0).reg();
+  const Register result = locs()->out(0).reg();
+  __ seqz(result, input);
+  __ slli(result, result, kBoolValueBitPosition);
+  __ add(result, result, NULL_REG);
+  __ addi(result, result, kTrueOffsetFromNull);
+}
+
 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,
                                                           bool opt) const {
   const intptr_t kNumInputs = (type_arguments() != nullptr) ? 1 : 0;
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index b7bca3f..c91ed77 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -567,7 +567,12 @@
       __ LoadObject(destination.reg(), value_);
     }
   } else if (destination.IsFpuRegister()) {
-    __ LoadDImmediate(destination.fpu_reg(), Double::Cast(value_).value());
+    if (representation() == kUnboxedFloat) {
+      __ LoadSImmediate(destination.fpu_reg(), Double::Cast(value_).value());
+    } else {
+      ASSERT(representation() == kUnboxedDouble);
+      __ LoadDImmediate(destination.fpu_reg(), Double::Cast(value_).value());
+    }
   } else if (destination.IsDoubleStackSlot()) {
     __ LoadDImmediate(FpuTMP, Double::Cast(value_).value());
     __ movsd(LocationToStackSlotAddress(destination), FpuTMP);
@@ -5043,35 +5048,6 @@
 
 #undef DEFINE_EMIT
 
-LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
-                                                     bool opt) const {
-  ASSERT((kind() == MathUnaryInstr::kSqrt) ||
-         (kind() == MathUnaryInstr::kDoubleSquare));
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresFpuRegister());
-  if (kind() == MathUnaryInstr::kDoubleSquare) {
-    summary->set_out(0, Location::SameAsFirstInput());
-  } else {
-    summary->set_out(0, Location::RequiresFpuRegister());
-  }
-  return summary;
-}
-
-void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (kind() == MathUnaryInstr::kSqrt) {
-    __ sqrtsd(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
-  } else if (kind() == MathUnaryInstr::kDoubleSquare) {
-    XmmRegister value_reg = locs()->in(0).fpu_reg();
-    __ mulsd(value_reg, value_reg);
-    ASSERT(value_reg == locs()->out(0).fpu_reg());
-  } else {
-    UNREACHABLE();
-  }
-}
-
 LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
     Zone* zone,
     bool opt) const {
@@ -5129,14 +5105,39 @@
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresFpuRegister());
-  summary->set_out(0, Location::SameAsFirstInput());
+  summary->set_out(0, Location::RequiresFpuRegister());
   return summary;
 }
 
 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ASSERT(representation() == kUnboxedDouble);
+  XmmRegister result = locs()->out(0).fpu_reg();
   XmmRegister value = locs()->in(0).fpu_reg();
-  ASSERT(locs()->out(0).fpu_reg() == value);
-  __ DoubleNegate(value, value);
+  switch (op_kind()) {
+    case Token::kNEGATE:
+      __ DoubleNegate(result, value);
+      break;
+    case Token::kSQRT:
+      __ sqrtsd(result, value);
+      break;
+    case Token::kSQUARE:
+      if (result != value) {
+        __ movsd(result, value);
+      }
+      __ mulsd(result, value);
+      break;
+    case Token::kTRUNCATE:
+      __ roundsd(result, value, compiler::Assembler::kRoundToZero);
+      break;
+    case Token::kFLOOR:
+      __ roundsd(result, value, compiler::Assembler::kRoundDown);
+      break;
+    case Token::kCEILING:
+      __ roundsd(result, value, compiler::Assembler::kRoundUp);
+      break;
+    default:
+      UNREACHABLE();
+  }
 }
 
 LocationSummary* MathMinMaxInstr::MakeLocationSummary(Zone* zone,
@@ -5361,40 +5362,6 @@
   __ SmiTag(result);
 }
 
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone,
-                                                          bool opt) const {
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* result = new (zone)
-      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  result->set_in(0, Location::RequiresFpuRegister());
-  result->set_out(0, Location::RequiresFpuRegister());
-  return result;
-}
-
-void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  XmmRegister value = locs()->in(0).fpu_reg();
-  XmmRegister result = locs()->out(0).fpu_reg();
-  if (value != result) {
-    // Clear full register to avoid false dependency due to
-    // a partial access to XMM register in roundsd instruction.
-    __ xorps(result, result);
-  }
-  switch (recognized_kind()) {
-    case MethodRecognizer::kDoubleTruncateToDouble:
-      __ roundsd(result, value, compiler::Assembler::kRoundToZero);
-      break;
-    case MethodRecognizer::kDoubleFloorToDouble:
-      __ roundsd(result, value, compiler::Assembler::kRoundDown);
-      break;
-    case MethodRecognizer::kDoubleCeilToDouble:
-      __ roundsd(result, value, compiler::Assembler::kRoundUp);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
                                                          bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -5425,6 +5392,16 @@
   __ cvtss2sd(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
 }
 
+LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
+                                                        bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(Zone* zone,
                                                                bool opt) const {
   // Calling convention on x64 uses XMM0 and XMM1 to pass the first two
@@ -5650,6 +5627,26 @@
   }
 }
 
+LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
+                                                    bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -7012,6 +7009,26 @@
                       compiler::target::ObjectAlignment::kBoolValueMask));
 }
 
+LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
+                                                     bool opt) const {
+  UNREACHABLE();
+  return NULL;
+}
+
+void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,
                                                           bool opt) const {
   const intptr_t kNumInputs = (type_arguments() != nullptr) ? 1 : 0;
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index dd8279d..7fdd085 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -78,6 +78,7 @@
             "Max. number of inlined calls per depth");
 DEFINE_FLAG(bool, print_inlining_tree, false, "Print inlining tree");
 
+DECLARE_FLAG(bool, enable_simd_inline);
 DECLARE_FLAG(int, max_deoptimization_counter_threshold);
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
@@ -807,7 +808,8 @@
   for (intptr_t i = 0; i < defns->length(); ++i) {
     ConstantInstr* constant = (*defns)[i]->AsConstant();
     if (constant != nullptr && constant->HasUses()) {
-      constant->ReplaceUsesWith(caller_graph->GetConstant(constant->value()));
+      constant->ReplaceUsesWith(caller_graph->GetConstant(
+          constant->value(), constant->representation()));
     }
   }
 
@@ -815,7 +817,8 @@
   for (intptr_t i = 0; i < defns->length(); ++i) {
     ConstantInstr* constant = (*defns)[i]->AsConstant();
     if (constant != nullptr && constant->HasUses()) {
-      constant->ReplaceUsesWith(caller_graph->GetConstant(constant->value()));
+      constant->ReplaceUsesWith(caller_graph->GetConstant(
+          constant->value(), constant->representation()));
     }
 
     SpecialParameterInstr* param = (*defns)[i]->AsSpecialParameter();
@@ -3537,6 +3540,585 @@
   return true;
 }
 
+class SimdLowering : public ValueObject {
+ public:
+  SimdLowering(FlowGraph* flow_graph,
+               Instruction* call,
+               GraphEntryInstr* graph_entry,
+               FunctionEntryInstr** entry,
+               Instruction** last,
+               Definition** result)
+      : flow_graph_(flow_graph),
+        call_(call),
+        graph_entry_(graph_entry),
+        entry_(entry),
+        last_(last),
+        result_(result) {
+    *entry_ = new (zone())
+        FunctionEntryInstr(graph_entry_, flow_graph_->allocate_block_id(),
+                           call_->GetBlock()->try_index(), call_->deopt_id());
+    *last = *entry_;
+  }
+
+  bool TryInline(MethodRecognizer::Kind kind) {
+    switch (kind) {
+      // ==== Int32x4 ====
+      case MethodRecognizer::kInt32x4FromInts:
+        UnboxScalar(0, kUnboxedInt32, 4);
+        UnboxScalar(1, kUnboxedInt32, 4);
+        UnboxScalar(2, kUnboxedInt32, 4);
+        UnboxScalar(3, kUnboxedInt32, 4);
+        Gather(4);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      case MethodRecognizer::kInt32x4FromBools:
+        UnboxBool(0, 4);
+        UnboxBool(1, 4);
+        UnboxBool(2, 4);
+        UnboxBool(3, 4);
+        Gather(4);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      case MethodRecognizer::kInt32x4GetFlagX:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        IntToBool();
+        Return(0);
+        return true;
+      case MethodRecognizer::kInt32x4GetFlagY:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        IntToBool();
+        Return(1);
+        return true;
+      case MethodRecognizer::kInt32x4GetFlagZ:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        IntToBool();
+        Return(2);
+        return true;
+      case MethodRecognizer::kInt32x4GetFlagW:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        IntToBool();
+        Return(3);
+        return true;
+      case MethodRecognizer::kInt32x4WithFlagX:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        UnboxBool(1, 4);
+        With(0);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      case MethodRecognizer::kInt32x4WithFlagY:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        UnboxBool(1, 4);
+        With(1);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      case MethodRecognizer::kInt32x4WithFlagZ:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        UnboxBool(1, 4);
+        With(2);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      case MethodRecognizer::kInt32x4WithFlagW:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        UnboxBool(1, 4);
+        With(3);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      case MethodRecognizer::kInt32x4Shuffle: {
+        Definition* mask_definition =
+            call_->ArgumentAt(call_->ArgumentCount() - 1);
+        intptr_t mask = 0;
+        if (!CheckMask(mask_definition, &mask)) {
+          return false;
+        }
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        Shuffle(mask);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      }
+      case MethodRecognizer::kInt32x4ShuffleMix: {
+        Definition* mask_definition =
+            call_->ArgumentAt(call_->ArgumentCount() - 1);
+        intptr_t mask = 0;
+        if (!CheckMask(mask_definition, &mask)) {
+          return false;
+        }
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4);
+        UnboxVector(1, kUnboxedInt32, kMintCid, 4);
+        ShuffleMix(mask);
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      }
+      case MethodRecognizer::kInt32x4GetSignMask:
+      case MethodRecognizer::kInt32x4Select:
+        // TODO(riscv)
+        return false;
+
+      // ==== Float32x4 ====
+      case MethodRecognizer::kFloat32x4Abs:
+        Float32x4Unary(Token::kABS);
+        return true;
+      case MethodRecognizer::kFloat32x4Negate:
+        Float32x4Unary(Token::kNEGATE);
+        return true;
+      case MethodRecognizer::kFloat32x4Sqrt:
+        Float32x4Unary(Token::kSQRT);
+        return true;
+      case MethodRecognizer::kFloat32x4Reciprocal:
+        Float32x4Unary(Token::kRECIPROCAL);
+        return true;
+      case MethodRecognizer::kFloat32x4ReciprocalSqrt:
+        Float32x4Unary(Token::kRECIPROCAL_SQRT);
+        return true;
+      case MethodRecognizer::kFloat32x4GetSignMask:
+        // TODO(riscv)
+        return false;
+      case MethodRecognizer::kFloat32x4Equal:
+        Float32x4Compare(Token::kEQ);
+        return true;
+      case MethodRecognizer::kFloat32x4GreaterThan:
+        Float32x4Compare(Token::kGT);
+        return true;
+      case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
+        Float32x4Compare(Token::kGTE);
+        return true;
+      case MethodRecognizer::kFloat32x4LessThan:
+        Float32x4Compare(Token::kLT);
+        return true;
+      case MethodRecognizer::kFloat32x4LessThanOrEqual:
+        Float32x4Compare(Token::kLTE);
+        return true;
+      case MethodRecognizer::kFloat32x4Add:
+        Float32x4Binary(Token::kADD);
+        return true;
+      case MethodRecognizer::kFloat32x4Sub:
+        Float32x4Binary(Token::kSUB);
+        return true;
+      case MethodRecognizer::kFloat32x4Mul:
+        Float32x4Binary(Token::kMUL);
+        return true;
+      case MethodRecognizer::kFloat32x4Div:
+        Float32x4Binary(Token::kDIV);
+        return true;
+      case MethodRecognizer::kFloat32x4Min:
+        Float32x4Binary(Token::kMIN);
+        return true;
+      case MethodRecognizer::kFloat32x4Max:
+        Float32x4Binary(Token::kMAX);
+        return true;
+      case MethodRecognizer::kFloat32x4Scale:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        UnboxScalar(1, kUnboxedFloat, 4);
+        BinaryDoubleOp(Token::kMUL, kUnboxedFloat, 4);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4Splat:
+        UnboxScalar(0, kUnboxedFloat, 4);
+        Splat(4);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4WithX:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        UnboxScalar(1, kUnboxedFloat, 4);
+        With(0);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4WithY:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        UnboxScalar(1, kUnboxedFloat, 4);
+        With(1);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4WithZ:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        UnboxScalar(1, kUnboxedFloat, 4);
+        With(2);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4WithW:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        UnboxScalar(1, kUnboxedFloat, 4);
+        With(3);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4Zero:
+        UnboxDoubleZero(kUnboxedFloat, 4);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4FromDoubles:
+        UnboxScalar(0, kUnboxedFloat, 4);
+        UnboxScalar(1, kUnboxedFloat, 4);
+        UnboxScalar(2, kUnboxedFloat, 4);
+        UnboxScalar(3, kUnboxedFloat, 4);
+        Gather(4);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4GetX:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        BoxScalar(0, kUnboxedFloat);
+        return true;
+      case MethodRecognizer::kFloat32x4GetY:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        BoxScalar(1, kUnboxedFloat);
+        return true;
+      case MethodRecognizer::kFloat32x4GetZ:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        BoxScalar(2, kUnboxedFloat);
+        return true;
+      case MethodRecognizer::kFloat32x4GetW:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        BoxScalar(3, kUnboxedFloat);
+        return true;
+      case MethodRecognizer::kFloat32x4Shuffle: {
+        Definition* mask_definition =
+            call_->ArgumentAt(call_->ArgumentCount() - 1);
+        intptr_t mask = 0;
+        if (!CheckMask(mask_definition, &mask)) {
+          return false;
+        }
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        Shuffle(mask);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      }
+      case MethodRecognizer::kFloat32x4ShuffleMix: {
+        Definition* mask_definition =
+            call_->ArgumentAt(call_->ArgumentCount() - 1);
+        intptr_t mask = 0;
+        if (!CheckMask(mask_definition, &mask)) {
+          return false;
+        }
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+        UnboxVector(1, kUnboxedFloat, kDoubleCid, 4);
+        ShuffleMix(mask);
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      }
+
+      // ==== Float64x2 ====
+      case MethodRecognizer::kFloat64x2Abs:
+        Float64x2Unary(Token::kABS);
+        return true;
+      case MethodRecognizer::kFloat64x2Negate:
+        Float64x2Unary(Token::kNEGATE);
+        return true;
+      case MethodRecognizer::kFloat64x2Sqrt:
+        Float64x2Unary(Token::kSQRT);
+        return true;
+      case MethodRecognizer::kFloat64x2Add:
+        Float64x2Binary(Token::kADD);
+        return true;
+      case MethodRecognizer::kFloat64x2Sub:
+        Float64x2Binary(Token::kSUB);
+        return true;
+      case MethodRecognizer::kFloat64x2Mul:
+        Float64x2Binary(Token::kMUL);
+        return true;
+      case MethodRecognizer::kFloat64x2Div:
+        Float64x2Binary(Token::kDIV);
+        return true;
+      case MethodRecognizer::kFloat64x2Min:
+        Float64x2Binary(Token::kMIN);
+        return true;
+      case MethodRecognizer::kFloat64x2Max:
+        Float64x2Binary(Token::kMAX);
+        return true;
+      case MethodRecognizer::kFloat64x2Scale:
+        UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+        UnboxScalar(1, kUnboxedDouble, 2);
+        BinaryDoubleOp(Token::kMUL, kUnboxedDouble, 2);
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      case MethodRecognizer::kFloat64x2Splat:
+        UnboxScalar(0, kUnboxedDouble, 2);
+        Splat(2);
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      case MethodRecognizer::kFloat64x2WithX:
+        UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+        UnboxScalar(1, kUnboxedDouble, 2);
+        With(0);
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      case MethodRecognizer::kFloat64x2WithY:
+        UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+        UnboxScalar(1, kUnboxedDouble, 2);
+        With(1);
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      case MethodRecognizer::kFloat64x2Zero:
+        UnboxDoubleZero(kUnboxedDouble, 2);
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      case MethodRecognizer::kFloat64x2FromDoubles:
+        UnboxScalar(0, kUnboxedDouble, 2);
+        UnboxScalar(1, kUnboxedDouble, 2);
+        Gather(2);
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      case MethodRecognizer::kFloat64x2GetX:
+        UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+        BoxScalar(0, kUnboxedDouble);
+        return true;
+      case MethodRecognizer::kFloat64x2GetY:
+        UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+        BoxScalar(1, kUnboxedDouble);
+        return true;
+
+      // Mixed
+      case MethodRecognizer::kFloat32x4ToFloat64x2: {
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4, 1);
+        Float32x4ToFloat64x2();
+        BoxVector(kUnboxedDouble, 2);
+        return true;
+      }
+      case MethodRecognizer::kFloat64x2ToFloat32x4: {
+        UnboxVector(0, kUnboxedDouble, kDoubleCid, 2, 1);
+        Float64x2ToFloat32x4();
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      }
+      case MethodRecognizer::kInt32x4ToFloat32x4:
+        UnboxVector(0, kUnboxedInt32, kMintCid, 4, 1);
+        Int32x4ToFloat32x4();
+        BoxVector(kUnboxedFloat, 4);
+        return true;
+      case MethodRecognizer::kFloat32x4ToInt32x4:
+        UnboxVector(0, kUnboxedFloat, kDoubleCid, 4, 1);
+        Float32x4ToInt32x4();
+        BoxVector(kUnboxedInt32, 4);
+        return true;
+      default:
+        return false;
+    }
+  }
+
+ private:
+  void Float32x4Unary(Token::Kind op) {
+    UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+    UnaryDoubleOp(op, kUnboxedFloat, 4);
+    BoxVector(kUnboxedFloat, 4);
+  }
+  void Float32x4Binary(Token::Kind op) {
+    UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+    UnboxVector(1, kUnboxedFloat, kDoubleCid, 4);
+    BinaryDoubleOp(op, kUnboxedFloat, 4);
+    BoxVector(kUnboxedFloat, 4);
+  }
+  void Float32x4Compare(Token::Kind op) {
+    UnboxVector(0, kUnboxedFloat, kDoubleCid, 4);
+    UnboxVector(1, kUnboxedFloat, kDoubleCid, 4);
+    FloatCompare(op);
+    BoxVector(kUnboxedInt32, 4);
+  }
+  void Float64x2Unary(Token::Kind op) {
+    UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+    UnaryDoubleOp(op, kUnboxedDouble, 2);
+    BoxVector(kUnboxedDouble, 2);
+  }
+  void Float64x2Binary(Token::Kind op) {
+    UnboxVector(0, kUnboxedDouble, kDoubleCid, 2);
+    UnboxVector(1, kUnboxedDouble, kDoubleCid, 2);
+    BinaryDoubleOp(op, kUnboxedDouble, 2);
+    BoxVector(kUnboxedDouble, 2);
+  }
+
+  void UnboxVector(intptr_t i,
+                   Representation rep,
+                   intptr_t cid,
+                   intptr_t n,
+                   intptr_t type_args = 0) {
+    Definition* arg = call_->ArgumentAt(i + type_args);
+    if (CompilerState::Current().is_aot()) {
+      // Add null-checks in case of the arguments are known to be compatible
+      // but they are possibly nullable.
+      // By inserting the null-check, we can allow the unbox instruction later
+      // inserted to be non-speculative.
+      arg = AddDefinition(new (zone()) CheckNullInstr(
+          new (zone()) Value(arg), Symbols::SecondArg(), call_->deopt_id(),
+          call_->source(), CheckNullInstr::kArgumentError));
+    }
+    for (intptr_t lane = 0; lane < n; lane++) {
+      in_[i][lane] = AddDefinition(
+          new (zone()) UnboxLaneInstr(new (zone()) Value(arg), lane, rep, cid));
+    }
+  }
+
+  void UnboxScalar(intptr_t i,
+                   Representation rep,
+                   intptr_t n,
+                   intptr_t type_args = 0) {
+    Definition* arg = call_->ArgumentAt(i + type_args);
+    if (CompilerState::Current().is_aot()) {
+      // Add null-checks in case of the arguments are known to be compatible
+      // but they are possibly nullable.
+      // By inserting the null-check, we can allow the unbox instruction later
+      // inserted to be non-speculative.
+      arg = AddDefinition(new (zone()) CheckNullInstr(
+          new (zone()) Value(arg), Symbols::SecondArg(), call_->deopt_id(),
+          call_->source(), CheckNullInstr::kArgumentError));
+    }
+    Definition* unbox = AddDefinition(
+        UnboxInstr::Create(rep, new (zone()) Value(arg), DeoptId::kNone,
+                           Instruction::kNotSpeculative));
+    for (intptr_t lane = 0; lane < n; lane++) {
+      in_[i][lane] = unbox;
+    }
+  }
+
+  void UnboxBool(intptr_t i, intptr_t n) {
+    Definition* unbox = AddDefinition(new (zone()) BoolToIntInstr(
+        call_->ArgumentValueAt(i)->CopyWithType(zone())));
+    for (intptr_t lane = 0; lane < n; lane++) {
+      in_[i][lane] = unbox;
+    }
+  }
+
+  void UnboxDoubleZero(Representation rep, intptr_t n) {
+    Definition* zero = flow_graph_->GetConstant(
+        Double::ZoneHandle(Double::NewCanonical(0.0)), rep);
+    for (intptr_t lane = 0; lane < n; lane++) {
+      op_[lane] = zero;
+    }
+  }
+
+  void UnaryDoubleOp(Token::Kind op, Representation rep, intptr_t n) {
+    for (intptr_t lane = 0; lane < n; lane++) {
+      op_[lane] = AddDefinition(new (zone()) UnaryDoubleOpInstr(
+          op, new (zone()) Value(in_[0][lane]), call_->deopt_id(),
+          Instruction::kNotSpeculative, rep));
+    }
+  }
+
+  void BinaryDoubleOp(Token::Kind op, Representation rep, intptr_t n) {
+    for (intptr_t lane = 0; lane < n; lane++) {
+      op_[lane] = AddDefinition(new (zone()) BinaryDoubleOpInstr(
+          op, new (zone()) Value(in_[0][lane]),
+          new (zone()) Value(in_[1][lane]), call_->deopt_id(), call_->source(),
+          Instruction::kNotSpeculative, rep));
+    }
+  }
+
+  void FloatCompare(Token::Kind op) {
+    for (intptr_t lane = 0; lane < 4; lane++) {
+      op_[lane] = AddDefinition(
+          new (zone()) FloatCompareInstr(op, new (zone()) Value(in_[0][lane]),
+                                         new (zone()) Value(in_[1][lane])));
+    }
+  }
+
+  void With(intptr_t i) {
+    for (intptr_t lane = 0; lane < 4; lane++) {
+      op_[lane] = in_[0][lane];
+    }
+    op_[i] = in_[1][0];
+  }
+  void Splat(intptr_t n) {
+    for (intptr_t lane = 0; lane < n; lane++) {
+      op_[lane] = in_[0][0];
+    }
+  }
+  void Gather(intptr_t n) {
+    for (intptr_t lane = 0; lane < n; lane++) {
+      op_[lane] = in_[lane][0];
+    }
+  }
+  void Shuffle(intptr_t mask) {
+    op_[0] = in_[0][(mask >> 0) & 3];
+    op_[1] = in_[0][(mask >> 2) & 3];
+    op_[2] = in_[0][(mask >> 4) & 3];
+    op_[3] = in_[0][(mask >> 6) & 3];
+  }
+  void ShuffleMix(intptr_t mask) {
+    op_[0] = in_[0][(mask >> 0) & 3];
+    op_[1] = in_[0][(mask >> 2) & 3];
+    op_[2] = in_[1][(mask >> 4) & 3];
+    op_[3] = in_[1][(mask >> 6) & 3];
+  }
+  void Float32x4ToFloat64x2() {
+    for (intptr_t lane = 0; lane < 2; lane++) {
+      op_[lane] = AddDefinition(new (zone()) FloatToDoubleInstr(
+          new (zone()) Value(in_[0][lane]), DeoptId::kNone));
+    }
+  }
+  void Float64x2ToFloat32x4() {
+    for (intptr_t lane = 0; lane < 2; lane++) {
+      op_[lane] = AddDefinition(new (zone()) DoubleToFloatInstr(
+          new (zone()) Value(in_[0][lane]), DeoptId::kNone));
+    }
+    Definition* zero = flow_graph_->GetConstant(
+        Double::ZoneHandle(Double::NewCanonical(0.0)), kUnboxedFloat);
+    op_[2] = zero;
+    op_[3] = zero;
+  }
+  void Int32x4ToFloat32x4() {
+    for (intptr_t lane = 0; lane < 4; lane++) {
+      op_[lane] = AddDefinition(new (zone()) BitCastInstr(
+          kUnboxedInt32, kUnboxedFloat, new (zone()) Value(in_[0][lane])));
+    }
+  }
+  void Float32x4ToInt32x4() {
+    for (intptr_t lane = 0; lane < 4; lane++) {
+      op_[lane] = AddDefinition(new (zone()) BitCastInstr(
+          kUnboxedFloat, kUnboxedInt32, new (zone()) Value(in_[0][lane])));
+    }
+  }
+  void IntToBool() {
+    for (intptr_t lane = 0; lane < 4; lane++) {
+      op_[lane] = AddDefinition(
+          new (zone()) IntToBoolInstr(new (zone()) Value(in_[0][lane])));
+    }
+  }
+
+  void BoxVector(Representation rep, intptr_t n) {
+    Definition* box;
+    if (n == 2) {
+      box = new (zone()) BoxLanesInstr(rep, new (zone()) Value(op_[0]),
+                                       new (zone()) Value(op_[1]));
+    } else {
+      ASSERT(n == 4);
+      box = new (zone()) BoxLanesInstr(
+          rep, new (zone()) Value(op_[0]), new (zone()) Value(op_[1]),
+          new (zone()) Value(op_[2]), new (zone()) Value(op_[3]));
+    }
+    Done(AddDefinition(box));
+  }
+
+  void BoxScalar(intptr_t lane, Representation rep) {
+    Definition* box = BoxInstr::Create(rep, new (zone()) Value(in_[0][lane]));
+    Done(AddDefinition(box));
+  }
+
+  void Return(intptr_t lane) { Done(op_[lane]); }
+
+  void Done(Definition* result) {
+    // InheritDeoptTarget also inherits environment (which may add 'entry' into
+    // env_use_list()), so InheritDeoptTarget should be done only after decided
+    // to inline.
+    (*entry_)->InheritDeoptTarget(zone(), call_);
+    *result_ = result;
+  }
+
+  Definition* AddDefinition(Definition* def) {
+    *last_ = flow_graph_->AppendTo(
+        *last_, def, call_->deopt_id() != DeoptId::kNone ? call_->env() : NULL,
+        FlowGraph::kValue);
+    return def;
+  }
+  Zone* zone() { return flow_graph_->zone(); }
+
+  FlowGraph* flow_graph_;
+  Instruction* call_;
+  GraphEntryInstr* graph_entry_;
+  FunctionEntryInstr** entry_;
+  Instruction** last_;
+  Definition** result_;
+
+  // First index is the argment number, second index is the lane number.
+  Definition* in_[4][4];
+  // Index is the lane number.
+  Definition* op_[4];
+};
+
 static bool InlineSimdOp(FlowGraph* flow_graph,
                          bool is_dynamic_call,
                          Instruction* call,
@@ -3546,9 +4128,6 @@
                          FunctionEntryInstr** entry,
                          Instruction** last,
                          Definition** result) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
   if (is_dynamic_call && call->ArgumentCount() > 1) {
     // Issue(dartbug.com/37737): Dynamic invocation forwarders have the
     // same recognized kind as the method they are forwarding to.
@@ -3563,6 +4142,19 @@
     return false;
   }
 
+  if (!FLAG_enable_simd_inline) {
+    return false;
+  }
+
+  if (!FlowGraphCompiler::SupportsUnboxedSimd128()) {
+#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
+    SimdLowering lowering(flow_graph, call, graph_entry, entry, last, result);
+    return lowering.TryInline(kind);
+#else
+    UNREACHABLE();
+#endif
+  }
+
   *entry =
       new (Z) FunctionEntryInstr(graph_entry, flow_graph->allocate_block_id(),
                                  call->GetBlock()->try_index(), DeoptId::kNone);
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index b9804d5..f4e263b 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1323,6 +1323,14 @@
   return CompileType::Bool();
 }
 
+CompileType BoolToIntInstr::ComputeType() const {
+  return CompileType::Int();
+}
+
+CompileType IntToBoolInstr::ComputeType() const {
+  return CompileType::Bool();
+}
+
 CompileType InstanceOfInstr::ComputeType() const {
   return CompileType::Bool();
 }
@@ -1754,10 +1762,6 @@
   return CompileType::FromCid(simd_op_result_cids[kind()]);
 }
 
-CompileType MathUnaryInstr::ComputeType() const {
-  return CompileType::FromCid(kDoubleCid);
-}
-
 CompileType MathMinMaxInstr::ComputeType() const {
   return CompileType::FromCid(result_cid_);
 }
@@ -1811,6 +1815,20 @@
   }
 }
 
+CompileType BoxLanesInstr::ComputeType() const {
+  switch (from_representation()) {
+    case kUnboxedFloat:
+      return CompileType::FromCid(kFloat32x4Cid);
+    case kUnboxedDouble:
+      return CompileType::FromCid(kFloat64x2Cid);
+    case kUnboxedInt32:
+      return CompileType::FromCid(kInt32x4Cid);
+    default:
+      UNREACHABLE();
+      return CompileType::Dynamic();
+  }
+}
+
 CompileType Int32ToDoubleInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
@@ -1823,12 +1841,12 @@
   return CompileType::FromCid(kDoubleCid);
 }
 
-CompileType DoubleToDoubleInstr::ComputeType() const {
+CompileType FloatToDoubleInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
-CompileType FloatToDoubleInstr::ComputeType() const {
-  return CompileType::FromCid(kDoubleCid);
+CompileType FloatCompareInstr::ComputeType() const {
+  return CompileType::Int();
 }
 
 CompileType DoubleToFloatInstr::ComputeType() const {
@@ -1848,6 +1866,10 @@
   return CompileType::FromCid(definition_cid_);
 }
 
+CompileType UnboxLaneInstr::ComputeType() const {
+  return CompileType::FromCid(definition_cid_);
+}
+
 static AbstractTypePtr ExtractElementTypeFromArrayType(
     const AbstractType& array_type) {
   if (array_type.IsTypeParameter()) {
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 7cd28de..c48dc65 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -1244,15 +1244,6 @@
   return Fragment(instr);
 }
 
-Fragment BaseFlowGraphBuilder::DoubleToDouble(
-    MethodRecognizer::Kind recognized_kind) {
-  Value* value = Pop();
-  auto* instr =
-      new (Z) DoubleToDoubleInstr(value, recognized_kind, GetNextDeoptId());
-  Push(instr);
-  return Fragment(instr);
-}
-
 Fragment BaseFlowGraphBuilder::DoubleToInteger(
     MethodRecognizer::Kind recognized_kind) {
   Value* value = Pop();
@@ -1262,9 +1253,10 @@
   return Fragment(instr);
 }
 
-Fragment BaseFlowGraphBuilder::MathUnary(MathUnaryInstr::MathUnaryKind kind) {
+Fragment BaseFlowGraphBuilder::UnaryDoubleOp(Token::Kind op) {
   Value* value = Pop();
-  auto* instr = new (Z) MathUnaryInstr(kind, value, GetNextDeoptId());
+  auto* instr = new (Z) UnaryDoubleOpInstr(op, value, GetNextDeoptId(),
+                                           Instruction::kNotSpeculative);
   Push(instr);
   return Fragment(instr);
 }
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index a91212e..0632510 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -455,18 +455,13 @@
   Fragment InvokeMathCFunction(MethodRecognizer::Kind recognized_kind,
                                intptr_t num_inputs);
 
-  // Pops double value and converts it to double as specified
-  // by the recognized method (kDoubleTruncateToDouble,
-  // kDoubleFloorToDouble or kDoubleCeilToDouble).
-  Fragment DoubleToDouble(MethodRecognizer::Kind recognized_kind);
-
   // Pops double value and converts it to int as specified
   // by the recognized method (kDoubleToInteger,
   // kDoubleFloorToInt or kDoubleCeilToInt).
   Fragment DoubleToInteger(MethodRecognizer::Kind recognized_kind);
 
   // Pops double value and applies unary math operation.
-  Fragment MathUnary(MathUnaryInstr::MathUnaryKind kind);
+  Fragment UnaryDoubleOp(Token::Kind op);
 
   // Records coverage for this position, if the current VM mode supports it.
   Fragment RecordCoverage(TokenPosition position);
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 1e3707e..b1cc2ff 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -1634,14 +1634,26 @@
           ((kind == MethodRecognizer::kDoubleTruncateToDouble) ||
            (kind == MethodRecognizer::kDoubleFloorToDouble) ||
            (kind == MethodRecognizer::kDoubleCeilToDouble))) {
-        body += DoubleToDouble(kind);
+        switch (kind) {
+          case MethodRecognizer::kDoubleTruncateToDouble:
+            body += UnaryDoubleOp(Token::kTRUNCATE);
+            break;
+          case MethodRecognizer::kDoubleFloorToDouble:
+            body += UnaryDoubleOp(Token::kFLOOR);
+            break;
+          case MethodRecognizer::kDoubleCeilToDouble:
+            body += UnaryDoubleOp(Token::kCEILING);
+            break;
+          default:
+            UNREACHABLE();
+        }
       } else {
         body += InvokeMathCFunction(kind, function.NumParameters());
       }
     } break;
     case MethodRecognizer::kMathSqrt: {
       body += LoadLocal(parsed_function_->RawParameterVariable(0));
-      body += MathUnary(MathUnaryInstr::kSqrt);
+      body += UnaryDoubleOp(Token::kSQRT);
     } break;
     case MethodRecognizer::kFinalizerBase_setIsolate:
       ASSERT_EQUAL(function.NumParameters(), 1);
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index b64d7dd..de229ac 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -395,15 +395,9 @@
                   static_cast<uint64_t>(Integer::Cast(value).AsInt64Value()));
               break;
             case kTypedDataFloat32ArrayCid:
-              // Although element of Float32 array is represented with Double,
-              // it is already converted to 32-bit float via DoubleToFloat
-              // instruction before it was stored.
-              // Reinterpret double value as float to get the value back.
               typed_data.SetFloat32(
                   element_offset,
-                  bit_cast<float, uint32_t>(
-                      static_cast<uint32_t>(bit_cast<uint64_t, double>(
-                          Double::Cast(value).value()))));
+                  static_cast<float>(Double::Cast(value).value()));
               break;
             case kTypedDataFloat64ArrayCid:
               typed_data.SetFloat64(element_offset,
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 20eec15..497c453 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -232,6 +232,7 @@
     case DeoptInstr::kInt32x4:
     case DeoptInstr::kFloat64x2:
     case DeoptInstr::kWord:
+    case DeoptInstr::kFloat:
     case DeoptInstr::kDouble:
     case DeoptInstr::kMint:
     case DeoptInstr::kMintPair:
@@ -668,6 +669,12 @@
   DISALLOW_COPY_AND_ASSIGN(DeoptFpuInstr);
 };
 
+typedef DeoptFpuInstr<DeoptInstr::kFloat,
+                      CatchEntryMove::SourceKind::kFloatSlot,
+                      float,
+                      DoublePtr>
+    DeoptFloatInstr;
+
 typedef DeoptFpuInstr<DeoptInstr::kDouble,
                       CatchEntryMove::SourceKind::kDoubleSlot,
                       double,
@@ -902,6 +909,8 @@
   switch (kind) {
     case kWord:
       return new DeoptWordInstr(source_index);
+    case kFloat:
+      return new DeoptFloatInstr(source_index);
     case kDouble:
       return new DeoptDoubleInstr(source_index);
     case kMint:
@@ -945,6 +954,8 @@
   switch (kind) {
     case kWord:
       return "word";
+    case kFloat:
+      return "float";
     case kDouble:
       return "double";
     case kMint:
@@ -1127,6 +1138,9 @@
             new (zone()) DeoptUint32Instr(ToCpuRegisterSource(source_loc));
         break;
       case kUnboxedFloat:
+        deopt_instr = new (zone()) DeoptFloatInstr(
+            ToFpuRegisterSource(source_loc, Location::kDoubleStackSlot));
+        break;
       case kUnboxedDouble:
         deopt_instr = new (zone()) DeoptDoubleInstr(
             ToFpuRegisterSource(source_loc, Location::kDoubleStackSlot));
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index cbd15c2..ccfff06 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -82,7 +82,15 @@
     return cpu_registers_[reg];
   }
 
-  double FpuRegisterValue(FpuRegister reg) const {
+  float FpuRegisterValueAsFloat(FpuRegister reg) const {
+    ASSERT(FlowGraphCompiler::SupportsUnboxedDoubles());
+    ASSERT(fpu_registers_ != NULL);
+    ASSERT(reg >= 0);
+    ASSERT(reg < kNumberOfFpuRegisters);
+    return *reinterpret_cast<float*>(&fpu_registers_[reg]);
+  }
+
+  double FpuRegisterValueAsDouble(FpuRegister reg) const {
     ASSERT(FlowGraphCompiler::SupportsUnboxedDoubles());
     ASSERT(fpu_registers_ != NULL);
     ASSERT(reg >= 0);
@@ -159,6 +167,11 @@
         idx, reinterpret_cast<ObjectPtr*>(slot), deferred_slots_);
   }
 
+  void DeferMaterialization(float value, DoublePtr* slot) {
+    deferred_slots_ = new DeferredDouble(
+        value, reinterpret_cast<ObjectPtr*>(slot), deferred_slots_);
+  }
+
   void DeferMaterialization(double value, DoublePtr* slot) {
     deferred_slots_ = new DeferredDouble(
         value, reinterpret_cast<ObjectPtr*>(slot), deferred_slots_);
@@ -267,6 +280,7 @@
     kRetAddress,
     kConstant,
     kWord,
+    kFloat,
     kDouble,
     kFloat32x4,
     kFloat64x2,
@@ -358,9 +372,16 @@
 };
 
 template <>
+struct RegisterReader<FpuRegister, float> {
+  static double Read(DeoptContext* context, FpuRegister reg) {
+    return context->FpuRegisterValueAsFloat(reg);
+  }
+};
+
+template <>
 struct RegisterReader<FpuRegister, double> {
   static double Read(DeoptContext* context, FpuRegister reg) {
-    return context->FpuRegisterValue(reg);
+    return context->FpuRegisterValueAsDouble(reg);
   }
 };
 
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 23e9aa2..0d71595 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -237,6 +237,10 @@
           value = *TaggedSlotAt(fp, move.src_slot());
           break;
 
+        case CatchEntryMove::SourceKind::kFloatSlot:
+          value = Double::New(*SlotAt<float>(fp, move.src_slot()));
+          break;
+
         case CatchEntryMove::SourceKind::kDoubleSlot:
           value = Double::New(*SlotAt<double>(fp, move.src_slot()));
           break;
@@ -369,6 +373,11 @@
       Utils::SNPrint(from, ARRAY_SIZE(from), "fp[%" Pd "]", src_slot());
       break;
 
+    case SourceKind::kFloatSlot:
+      Utils::SNPrint(from, ARRAY_SIZE(from), "f32 [fp + %" Pd "]",
+                     src_slot() * compiler::target::kWordSize);
+      break;
+
     case SourceKind::kDoubleSlot:
       Utils::SNPrint(from, ARRAY_SIZE(from), "f64 [fp + %" Pd "]",
                      src_slot() * compiler::target::kWordSize);
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 89090a6..f87201d 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -147,6 +147,7 @@
   enum class SourceKind {
     kConstant,
     kTaggedSlot,
+    kFloatSlot,
     kDoubleSlot,
     kFloat32x4Slot,
     kFloat64x2Slot,
diff --git a/runtime/vm/token.cc b/runtime/vm/token.cc
index ba33707..ad55e39 100644
--- a/runtime/vm/token.cc
+++ b/runtime/vm/token.cc
@@ -56,6 +56,8 @@
     case Token::kSHL:
     case Token::kSHR:
     case Token::kUSHR:
+    case Token::kMAX:
+    case Token::kMIN:
       return true;
     default:
       return false;
@@ -63,7 +65,21 @@
 }
 
 bool Token::IsUnaryArithmeticOperator(Token::Kind token) {
-  return (token == kBIT_NOT) || (token == kNEGATE);
+  switch (token) {
+    case Token::kBIT_NOT:
+    case Token::kNEGATE:
+    case Token::kABS:
+    case Token::kSQRT:
+    case Token::kSQUARE:
+    case Token::kRECIPROCAL:
+    case Token::kRECIPROCAL_SQRT:
+    case Token::kTRUNCATE:
+    case Token::kFLOOR:
+    case Token::kCEILING:
+      return true;
+    default:
+      return false;
+  }
 }
 
 bool Token::IsBinaryBitwiseOperator(Token::Kind token) {
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index e2fc074..174af7d 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -140,7 +140,17 @@
   TOK(kSCRIPTTAG, "#!", 0, kNoAttribute)                                       \
                                                                                \
   /* Support for optimized code */                                             \
-  TOK(kREM, "", 0, kNoAttribute)
+  TOK(kREM, "rem", 0, kNoAttribute)                                            \
+  TOK(kABS, "abs", 0, kNoAttribute)                                            \
+  TOK(kSQRT, "sqrt", 0, kNoAttribute)                                          \
+  TOK(kMIN, "min", 0, kNoAttribute)                                            \
+  TOK(kMAX, "max", 0, kNoAttribute)                                            \
+  TOK(kRECIPROCAL, "reciprocal", 0, kNoAttribute)                              \
+  TOK(kRECIPROCAL_SQRT, "reciprocal-sqrt", 0, kNoAttribute)                    \
+  TOK(kSQUARE, "square", 0, kNoAttribute)                                      \
+  TOK(kTRUNCATE, "truncate", 0, kNoAttribute)                                  \
+  TOK(kFLOOR, "floor", 0, kNoAttribute)                                        \
+  TOK(kCEILING, "ceiling", 0, kNoAttribute)
 
 // List of keywords. The list must be alphabetically ordered. The
 // keyword recognition code depends on the ordering.
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index ae7f8f3..6f210df 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -28225,7 +28225,20 @@
     throw new UnsupportedError("Not supported");
   }
 
+  factory SharedArrayBuffer([int? length]) {
+    if (length != null) {
+      return SharedArrayBuffer._create_1(length);
+    }
+    return SharedArrayBuffer._create_2();
+  }
+  static SharedArrayBuffer _create_1(length) =>
+      JS('SharedArrayBuffer', 'new SharedArrayBuffer(#)', length);
+  static SharedArrayBuffer _create_2() =>
+      JS('SharedArrayBuffer', 'new SharedArrayBuffer()');
+
   int? get byteLength native;
+
+  SharedArrayBuffer slice([int? begin, int? end]) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 7dce112..661b998 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -2456,21 +2456,75 @@
   Float32x4 operator /(Float32x4 other);
 
   /// Relational less than.
+  ///
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(this.x < other.x ? -1 : 0,
+  ///         this.y < other.y ? -1 : 0,
+  ///         this.z < other.z ? -1 : 0,
+  ///         this.w < other.w ? -1 : 0);
+  /// ```
   Int32x4 lessThan(Float32x4 other);
 
   /// Relational less than or equal.
+  ///
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(this.x <= other.x ? -1 : 0,
+  ///         this.y <= other.y ? -1 : 0,
+  ///         this.z <= other.z ? -1 : 0,
+  ///         this.w <= other.w ? -1 : 0);
+  /// ```
   Int32x4 lessThanOrEqual(Float32x4 other);
 
   /// Relational greater than.
+  ///
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(this.x > other.x ? -1 : 0,
+  ///         this.y > other.y ? -1 : 0,
+  ///         this.z > other.z ? -1 : 0,
+  ///         this.w > other.w ? -1 : 0);
+  /// ```
   Int32x4 greaterThan(Float32x4 other);
 
   /// Relational greater than or equal.
+  ///
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(this.x >= other.x ? -1 : 0,
+  ///         this.y >= other.y ? -1 : 0,
+  ///         this.z >= other.z ? -1 : 0,
+  ///         this.w >= other.w ? -1 : 0);
+  /// ```
   Int32x4 greaterThanOrEqual(Float32x4 other);
 
   /// Relational equal.
+  ///
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(this.x == other.x ? -1 : 0,
+  ///         this.y == other.y ? -1 : 0,
+  ///         this.z == other.z ? -1 : 0,
+  ///         this.w == other.w ? -1 : 0);
+  /// ```
   Int32x4 equal(Float32x4 other);
 
   /// Relational not-equal.
+  ///
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(this.x != other.x ? -1 : 0,
+  ///         this.y != other.y ? -1 : 0,
+  ///         this.z != other.z ? -1 : 0,
+  ///         this.w != other.w ? -1 : 0);
+  /// ```
   Int32x4 notEqual(Float32x4 other);
 
   /// Returns a copy of [this] each lane being scaled by [s].
@@ -2802,7 +2856,14 @@
 /// The lanes are "x", "y", "z", and "w" respectively.
 abstract class Int32x4 {
   external factory Int32x4(int x, int y, int z, int w);
+
+  /// Equivalent to:
+  ///
+  /// ```
+  /// Int32x4(x ? -1 : 0, y ? -1 : 0, z ? -1 : 0, w ? -1 : 0)
+  /// ```
   external factory Int32x4.bool(bool x, bool y, bool z, bool w);
+
   external factory Int32x4.fromFloat32x4Bits(Float32x4 x);
 
   /// The bit-wise or operator.
diff --git a/tools/VERSION b/tools/VERSION
index a27dd14..a7d80de 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 58
+PRERELEASE 59
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index 45493dc..e8d59ee 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -21240,8 +21240,12 @@
   },
   "SharedArrayBuffer": {
     "members": {
+      "SharedArrayBuffer": {},
       "byteLength": {
         "support_level": "untriaged"
+      },
+      "slice": {
+        "support_level": "untriaged"
       }
     },
     "support_level": "untriaged"
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index 4665656..597dc45 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -683,3 +683,10 @@
 callback PositionCallback = void(object position);
 
 interface MathMLElement : Element {};
+
+[DartSupplemental,
+  CustomConstructor,
+  Constructor(optional unsigned long length)
+] interface SharedArrayBuffer {
+    SharedArrayBuffer slice(optional unsigned long begin, optional unsigned long end);
+};