Version 2.17.0-284.0.dev

Merge commit '1377e006fbe8d1e22177c92662a222a96098e62d' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 0b5e2e4..765df26 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -69,7 +69,7 @@
       "name": "analysis_server",
       "rootUri": "../pkg/analysis_server",
       "packageUri": "lib/",
-      "languageVersion": "2.14"
+      "languageVersion": "2.15"
     },
     {
       "name": "analysis_server_client",
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 2eff1ad..2b8352b 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -16,21 +16,25 @@
 import 'package:analysis_server/src/computer/computer_highlights.dart';
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
-import 'package:analysis_server/src/domain_analytics.dart';
 import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/domain_diagnostic.dart';
-import 'package:analysis_server/src/domain_kythe.dart';
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/domains/analysis/occurrences.dart';
 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/flutter/flutter_domain.dart';
 import 'package:analysis_server/src/flutter/flutter_notifications.dart';
+import 'package:analysis_server/src/handler/legacy/analytics_enable.dart';
+import 'package:analysis_server/src/handler/legacy/analytics_is_enabled.dart';
+import 'package:analysis_server/src/handler/legacy/analytics_send_event.dart';
+import 'package:analysis_server/src/handler/legacy/analytics_send_timing.dart';
+import 'package:analysis_server/src/handler/legacy/diagnostic_get_diagnostics.dart';
+import 'package:analysis_server/src/handler/legacy/diagnostic_get_server_port.dart';
 import 'package:analysis_server/src/handler/legacy/execution_create_context.dart';
 import 'package:analysis_server/src/handler/legacy/execution_delete_context.dart';
 import 'package:analysis_server/src/handler/legacy/execution_get_suggestions.dart';
 import 'package:analysis_server/src/handler/legacy/execution_map_uri.dart';
 import 'package:analysis_server/src/handler/legacy/execution_set_subscriptions.dart';
+import 'package:analysis_server/src/handler/legacy/kythe_get_kythe_entries.dart';
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
 import 'package:analysis_server/src/operation/operation_analysis.dart';
 import 'package:analysis_server/src/plugin/notification_manager.dart';
@@ -81,16 +85,21 @@
   /// A map from the name of a request to a function used to create a request
   /// handler.
   static final Map<String, HandlerGenerator> handlerGenerators = {
-    EXECUTION_REQUEST_CREATE_CONTEXT: (server, request, cancellationToken) =>
-        ExecutionCreateContextHandler(server, request, cancellationToken),
-    EXECUTION_REQUEST_DELETE_CONTEXT: (server, request, cancellationToken) =>
-        ExecutionDeleteContextHandler(server, request, cancellationToken),
-    EXECUTION_REQUEST_GET_SUGGESTIONS: (server, request, cancellationToken) =>
-        ExecutionGetSuggestionsHandler(server, request, cancellationToken),
-    EXECUTION_REQUEST_MAP_URI: (server, request, cancellationToken) =>
-        ExecutionMapUriHandler(server, request, cancellationToken),
-    EXECUTION_REQUEST_SET_SUBSCRIPTIONS: (server, request, cancellationToken) =>
-        ExecutionSetSubscriptionsHandler(server, request, cancellationToken),
+    ANALYTICS_REQUEST_IS_ENABLED: AnalyticsIsEnabledHandler.new,
+    ANALYTICS_REQUEST_ENABLE: AnalyticsEnableHandler.new,
+    ANALYTICS_REQUEST_SEND_EVENT: AnalyticsSendEventHandler.new,
+    ANALYTICS_REQUEST_SEND_TIMING: AnalyticsSendTimingHandler.new,
+    //
+    DIAGNOSTIC_REQUEST_GET_DIAGNOSTICS: DiagnosticGetDiagnosticsHandler.new,
+    DIAGNOSTIC_REQUEST_GET_SERVER_PORT: DiagnosticGetServerPortHandler.new,
+    //
+    EXECUTION_REQUEST_CREATE_CONTEXT: ExecutionCreateContextHandler.new,
+    EXECUTION_REQUEST_DELETE_CONTEXT: ExecutionDeleteContextHandler.new,
+    EXECUTION_REQUEST_GET_SUGGESTIONS: ExecutionGetSuggestionsHandler.new,
+    EXECUTION_REQUEST_MAP_URI: ExecutionMapUriHandler.new,
+    EXECUTION_REQUEST_SET_SUBSCRIPTIONS: ExecutionSetSubscriptionsHandler.new,
+    //
+    KYTHE_REQUEST_GET_KYTHE_ENTRIES: KytheGetKytheEntriesHandler.new,
   };
 
   /// The channel from which requests are received and to which responses should
@@ -248,9 +257,6 @@
       EditDomainHandler(this),
       SearchDomainHandler(this),
       CompletionDomainHandler(this),
-      DiagnosticDomainHandler(this),
-      AnalyticsDomainHandler(this),
-      KytheDomainHandler(this),
       FlutterDomainHandler(this)
     ];
   }
diff --git a/pkg/analysis_server/lib/src/domain_analytics.dart b/pkg/analysis_server/lib/src/domain_analytics.dart
deleted file mode 100644
index caebdc3..0000000
--- a/pkg/analysis_server/lib/src/domain_analytics.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_constants.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/handler/legacy/analytics_enable.dart';
-import 'package:analysis_server/src/handler/legacy/analytics_is_enabled.dart';
-import 'package:analysis_server/src/handler/legacy/analytics_send_event.dart';
-import 'package:analysis_server/src/handler/legacy/analytics_send_timing.dart';
-import 'package:analyzer/src/utilities/cancellation.dart';
-
-/// Instances of the class [AnalyticsDomainHandler] implement a [RequestHandler]
-/// that handles requests in the `analytics` domain.
-class AnalyticsDomainHandler implements RequestHandler {
-  final AnalysisServer server;
-
-  AnalyticsDomainHandler(this.server);
-
-  @override
-  Response? handleRequest(
-      Request request, CancellationToken cancellationToken) {
-    var requestName = request.method;
-
-    if (requestName == ANALYTICS_REQUEST_IS_ENABLED) {
-      AnalyticsIsEnabledHandler(server, request, cancellationToken).handle();
-      return Response.DELAYED_RESPONSE;
-    } else if (requestName == ANALYTICS_REQUEST_ENABLE) {
-      AnalyticsEnableHandler(server, request, cancellationToken).handle();
-      return Response.DELAYED_RESPONSE;
-    } else if (requestName == ANALYTICS_REQUEST_SEND_EVENT) {
-      AnalyticsSendEventHandler(server, request, cancellationToken).handle();
-      return Response.DELAYED_RESPONSE;
-    } else if (requestName == ANALYTICS_REQUEST_SEND_TIMING) {
-      AnalyticsSendTimingHandler(server, request, cancellationToken).handle();
-      return Response.DELAYED_RESPONSE;
-    }
-    return null;
-  }
-}
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
deleted file mode 100644
index e3d2eb8..0000000
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_constants.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/handler/legacy/diagnostic_get_diagnostics.dart';
-import 'package:analysis_server/src/handler/legacy/diagnostic_get_server_port.dart';
-import 'package:analyzer/src/utilities/cancellation.dart';
-
-/// Instances of the class [DiagnosticDomainHandler] implement a
-/// [RequestHandler] that handles requests in the `diagnostic` domain.
-class DiagnosticDomainHandler implements RequestHandler {
-  /// The analysis server that is using this handler to process requests.
-  final AnalysisServer server;
-
-  /// Initialize a newly created handler to handle requests for the given
-  /// [server].
-  DiagnosticDomainHandler(this.server);
-
-  @override
-  Response? handleRequest(
-      Request request, CancellationToken cancellationToken) {
-    try {
-      var requestName = request.method;
-      if (requestName == DIAGNOSTIC_REQUEST_GET_DIAGNOSTICS) {
-        DiagnosticGetDiagnosticsHandler(server, request, cancellationToken)
-            .handle();
-        return Response.DELAYED_RESPONSE;
-      } else if (requestName == DIAGNOSTIC_REQUEST_GET_SERVER_PORT) {
-        DiagnosticGetServerPortHandler(server, request, cancellationToken)
-            .handle();
-        return Response.DELAYED_RESPONSE;
-      }
-    } on RequestFailure catch (exception) {
-      return exception.response;
-    }
-    return null;
-  }
-}
diff --git a/pkg/analysis_server/lib/src/domain_kythe.dart b/pkg/analysis_server/lib/src/domain_kythe.dart
deleted file mode 100644
index 9b62c45..0000000
--- a/pkg/analysis_server/lib/src/domain_kythe.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_constants.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/domain_abstract.dart';
-import 'package:analysis_server/src/handler/legacy/kythe_get_kythe_entries.dart';
-import 'package:analyzer/src/utilities/cancellation.dart';
-
-/// Instances of the class [KytheDomainHandler] implement a [RequestHandler]
-/// that handles requests in the `kythe` domain.
-class KytheDomainHandler extends AbstractRequestHandler {
-  /// Initialize a newly created handler to handle requests for the given
-  /// [server].
-  KytheDomainHandler(AnalysisServer server) : super(server);
-
-  @override
-  Response? handleRequest(
-      Request request, CancellationToken cancellationToken) {
-    try {
-      var requestName = request.method;
-      if (requestName == KYTHE_REQUEST_GET_KYTHE_ENTRIES) {
-        KytheGetKytheEntriesHandler(server, request, cancellationToken)
-            .handle();
-        return Response.DELAYED_RESPONSE;
-      }
-    } on RequestFailure catch (exception) {
-      return exception.response;
-    }
-    return null;
-  }
-}
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 5f62d61..e1680a0 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -3,7 +3,7 @@
 publish_to: none
 
 environment:
-  sdk: '>=2.14.0 <3.0.0'
+  sdk: '>=2.15.0 <3.0.0'
 
 dependencies:
   _fe_analyzer_shared:
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index 13b5829..dd79a90 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/domain_diagnostic.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -17,13 +16,6 @@
 
 @reflectiveTest
 class DiagnosticDomainTest extends AbstractAnalysisTest {
-  @override
-  void setUp() {
-    super.setUp();
-    handler = DiagnosticDomainHandler(server);
-    server.handlers = [handler];
-  }
-
   Future<void> test_getDiagnostics() async {
     newPubspecYamlFile('/project', 'name: project');
     newFile2('/project/bin/test.dart', 'main() {}');
diff --git a/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart b/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart
index c09c72e..2f6f70b 100644
--- a/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart
@@ -150,7 +150,8 @@
 
     var dartBinary = join(dartSdkPath, 'bin', 'dart');
 
-    var useSnapshot = true;
+    // Prevent flow analysis from marking code below as being dead.
+    const useSnapshot = 1 > 0;
     String serverPath;
 
     if (useSnapshot) {
diff --git a/pkg/analysis_server/test/integration/support/integration_tests.dart b/pkg/analysis_server/test/integration/support/integration_tests.dart
index ceb7185..7c9fd4c 100644
--- a/pkg/analysis_server/test/integration/support/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/support/integration_tests.dart
@@ -622,9 +622,8 @@
 
     var dartBinary = path.join(dartSdkPath, 'bin', 'dart');
 
-    // The integration tests run 3x faster when run from snapshots (you need to
-    // run test.py with --use-sdk).
-    var useSnapshot = true;
+    // Prevent flow analysis from marking code below as being dead.
+    const useSnapshot = 1 > 0;
     String serverPath;
 
     if (useSnapshot) {
diff --git a/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart b/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart
index cd03107..9451d5c 100644
--- a/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart
+++ b/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart
@@ -106,7 +106,7 @@
       Reference.root(),
     );
 
-    var linkResult = await link2(elementFactory, inputLibraries);
+    var linkResult = await link(elementFactory, inputLibraries);
 
     var bundleBuilder = PackageBundleBuilder();
     for (var library in inputLibraries) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 56950bb..695ffbf 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -83,7 +83,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 212;
+  static const int DATA_VERSION = 213;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index fa6f1f2..96dcbb7 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -20,7 +20,7 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary2/bundle_reader.dart';
-import 'package:analyzer/src/summary2/link.dart' as link2;
+import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/linked_element_factory.dart';
 import 'package:analyzer/src/summary2/macro.dart';
 import 'package:analyzer/src/summary2/reference.dart';
@@ -164,11 +164,11 @@
 
         timerInputLibraries.start();
         inputsTimer.start();
-        var inputLibraries = <link2.LinkInputLibrary>[];
+        var inputLibraries = <LinkInputLibrary>[];
         for (var libraryFile in cycle.libraries) {
           var librarySource = libraryFile.source;
 
-          var inputUnits = <link2.LinkInputUnit>[];
+          var inputUnits = <LinkInputUnit>[];
           var partIndex = -1;
           for (var file in libraryFile.libraryFiles) {
             var isSynthetic = !file.exists;
@@ -181,7 +181,7 @@
             partIndex++;
 
             inputUnits.add(
-              link2.LinkInputUnit(
+              LinkInputUnit(
                 // TODO(scheglov) bad, group part data
                 partDirectiveIndex: partIndex - 1,
                 partUriStr: partUriStr,
@@ -194,7 +194,7 @@
           }
 
           inputLibraries.add(
-            link2.LinkInputLibrary(
+            LinkInputLibrary(
               source: librarySource,
               units: inputUnits,
             ),
@@ -203,12 +203,10 @@
         inputsTimer.stop();
         timerInputLibraries.stop();
 
-        link2.LinkResult linkResult;
+        LinkResult linkResult;
         try {
           timerLinking.start();
-          // TODO(scheglov) Migrate when we are ready to switch to async.
-          // ignore: deprecated_member_use_from_same_package
-          linkResult = await link2.link2(elementFactory, inputLibraries);
+          linkResult = await link(elementFactory, inputLibraries);
           librariesLinked += cycle.libraries.length;
           counterLinkedLibraries += inputLibraries.length;
           timerLinking.stop();
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
index 1658a93..e1f1f9e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
@@ -6,8 +6,10 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/invokes_super_self.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
+import 'package:collection/collection.dart';
 
 /// Return the bytes of the unlinked API signature of the given [unit].
 ///
@@ -39,6 +41,10 @@
     for (var declaration in unit.declarations) {
       if (declaration is ClassOrMixinDeclaration) {
         _addClassOrMixin(declaration);
+      } else if (declaration is EnumDeclaration) {
+        _addEnum(declaration);
+      } else if (declaration is ExtensionDeclaration) {
+        _addExtension(declaration);
       } else if (declaration is FunctionDeclaration) {
         var functionExpression = declaration.functionExpression;
         _addTokens(
@@ -54,36 +60,70 @@
     }
   }
 
+  void _addClassMembers(List<ClassMember> members, bool hasConstConstructor) {
+    signature.addInt(members.length);
+    for (var member in members) {
+      if (member is ConstructorDeclaration) {
+        _addConstructorDeclaration(member);
+      } else if (member is FieldDeclaration) {
+        _addFieldDeclaration(member, hasConstConstructor);
+      } else if (member is MethodDeclaration) {
+        _addMethodDeclaration(member);
+      } else {
+        throw UnimplementedError('(${member.runtimeType}) $member');
+      }
+    }
+  }
+
   void _addClassOrMixin(ClassOrMixinDeclaration node) {
     _addTokens(node.beginToken, node.leftBracket);
 
     bool hasConstConstructor = node.members
         .any((m) => m is ConstructorDeclaration && m.constKeyword != null);
 
-    signature.addInt(node.members.length);
-    for (var member in node.members) {
-      if (member is ConstructorDeclaration) {
-        signature.addInt(_kindConstructorDeclaration);
-        _addTokens(member.beginToken, member.parameters.endToken);
-        _addNodeList(member.initializers);
-        _addNode(member.redirectedConstructor);
-      } else if (member is FieldDeclaration) {
-        signature.addInt(_kindFieldDeclaration);
-        _fieldDeclaration(member, hasConstConstructor);
-      } else if (member is MethodDeclaration) {
-        signature.addInt(_kindMethodDeclaration);
-        _addTokens(
-          member.beginToken,
-          (member.parameters ?? member.name).endToken,
-        );
-        signature.addBool(member.body is EmptyFunctionBody);
-        _addFunctionBodyModifiers(member.body);
-      } else {
-        throw UnimplementedError('(${member.runtimeType}) $member');
-      }
+    _addClassMembers(node.members, hasConstConstructor);
+  }
+
+  void _addConstructorDeclaration(ConstructorDeclaration node) {
+    signature.addInt(_kindConstructorDeclaration);
+    _addTokens(node.beginToken, node.parameters.endToken);
+    _addNodeList(node.initializers);
+    _addNode(node.redirectedConstructor);
+  }
+
+  void _addEnum(EnumDeclaration node) {
+    var members = node.members;
+
+    // If not enhanced, include the whole node.
+    var firstMember = members.firstOrNull;
+    if (firstMember == null) {
+      _addNode(node);
+      return;
     }
 
-    _addToken(node.rightBracket);
+    _addTokens(node.beginToken, firstMember.beginToken);
+    _addClassMembers(members, true);
+  }
+
+  void _addExtension(ExtensionDeclaration node) {
+    _addTokens(node.beginToken, node.leftBracket);
+    _addClassMembers(node.members, false);
+  }
+
+  void _addFieldDeclaration(FieldDeclaration node, bool hasConstConstructor) {
+    signature.addInt(_kindFieldDeclaration);
+
+    _addToken(node.abstractKeyword);
+    _addToken(node.covariantKeyword);
+    _addToken(node.externalKeyword);
+    _addToken(node.staticKeyword);
+    _addNodeList(node.metadata);
+
+    var variableList = node.fields;
+    var includeInitializers = variableList.type == null ||
+        variableList.isConst ||
+        hasConstConstructor && !node.isStatic && variableList.isFinal;
+    _variableList(variableList, includeInitializers);
   }
 
   void _addFunctionBodyModifiers(FunctionBody? node) {
@@ -93,6 +133,17 @@
     }
   }
 
+  void _addMethodDeclaration(MethodDeclaration node) {
+    signature.addInt(_kindMethodDeclaration);
+    _addTokens(
+      node.beginToken,
+      (node.parameters ?? node.name).endToken,
+    );
+    signature.addBool(node.body is EmptyFunctionBody);
+    _addFunctionBodyModifiers(node.body);
+    signature.addBool(node.invokesSuperSelf);
+  }
+
   void _addNode(AstNode? node) {
     if (node != null) {
       signature.addInt(_notNullNode);
@@ -142,20 +193,6 @@
     }
   }
 
-  void _fieldDeclaration(FieldDeclaration node, bool hasConstConstructor) {
-    _addToken(node.abstractKeyword);
-    _addToken(node.covariantKeyword);
-    _addToken(node.externalKeyword);
-    _addToken(node.staticKeyword);
-    _addNodeList(node.metadata);
-
-    var variableList = node.fields;
-    var includeInitializers = variableList.type == null ||
-        variableList.isConst ||
-        hasConstConstructor && !node.isStatic && variableList.isFinal;
-    _variableList(variableList, includeInitializers);
-  }
-
   void _topLevelVariableDeclaration(TopLevelVariableDeclaration node) {
     _addToken(node.externalKeyword);
     _addNodeList(node.metadata);
diff --git a/pkg/analyzer/lib/src/dart/ast/invokes_super_self.dart b/pkg/analyzer/lib/src/dart/ast/invokes_super_self.dart
new file mode 100644
index 0000000..76d4b1d
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/ast/invokes_super_self.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+
+class _SuperVisitor extends RecursiveAstVisitor<void> {
+  final String name;
+
+  /// Set to `true` if a super invocation with the [name] is found.
+  bool hasSuperInvocation = false;
+
+  _SuperVisitor(this.name);
+
+  @override
+  void visitAssignmentExpression(AssignmentExpression node) {
+    var left = node.leftHandSide;
+    if (left is PropertyAccess) {
+      if (left.target is SuperExpression && left.propertyName.name == name) {
+        hasSuperInvocation = true;
+        return;
+      }
+    }
+    super.visitAssignmentExpression(node);
+  }
+
+  @override
+  void visitBinaryExpression(BinaryExpression node) {
+    if (node.leftOperand is SuperExpression && node.operator.lexeme == name) {
+      hasSuperInvocation = true;
+      return;
+    }
+    super.visitBinaryExpression(node);
+  }
+
+  @override
+  void visitMethodInvocation(MethodInvocation node) {
+    if (node.target is SuperExpression && node.methodName.name == name) {
+      hasSuperInvocation = true;
+      return;
+    }
+    super.visitMethodInvocation(node);
+  }
+
+  @override
+  void visitPropertyAccess(PropertyAccess node) {
+    if (node.target is SuperExpression && node.propertyName.name == name) {
+      hasSuperInvocation = true;
+      return;
+    }
+    super.visitPropertyAccess(node);
+  }
+}
+
+extension MethodDeclarationExtension on MethodDeclaration {
+  bool get invokesSuperSelf {
+    var visitor = _SuperVisitor(name.name);
+    body.accept(visitor);
+    return visitor.hasSuperInvocation;
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/ast/mixin_super_invoked_names.dart b/pkg/analyzer/lib/src/dart/ast/mixin_super_invoked_names.dart
index b96dfe5..228c1d7 100644
--- a/pkg/analyzer/lib/src/dart/ast/mixin_super_invoked_names.dart
+++ b/pkg/analyzer/lib/src/dart/ast/mixin_super_invoked_names.dart
@@ -1,3 +1,7 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 5670310..989c73c 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -30,7 +30,7 @@
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/bundle_reader.dart';
-import 'package:analyzer/src/summary2/link.dart' as link2;
+import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/linked_element_factory.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/task/options.dart';
@@ -844,11 +844,11 @@
         librariesLinkedTimer.start();
 
         inputsTimer.start();
-        var inputLibraries = <link2.LinkInputLibrary>[];
+        var inputLibraries = <LinkInputLibrary>[];
         for (var libraryFile in cycle.libraries) {
           var librarySource = libraryFile.source;
 
-          var inputUnits = <link2.LinkInputUnit>[];
+          var inputUnits = <LinkInputUnit>[];
           var partIndex = -1;
           for (var file in libraryFile.files().ofLibrary) {
             var isSynthetic = !file.exists;
@@ -869,7 +869,7 @@
             partIndex++;
 
             inputUnits.add(
-              link2.LinkInputUnit(
+              LinkInputUnit(
                 // TODO(scheglov) bad, group part data
                 partDirectiveIndex: partIndex - 1,
                 partUriStr: partUriStr,
@@ -881,7 +881,7 @@
           }
 
           inputLibraries.add(
-            link2.LinkInputLibrary(
+            LinkInputLibrary(
               source: librarySource,
               units: inputUnits,
             ),
@@ -889,7 +889,7 @@
         }
         inputsTimer.stop();
 
-        var linkResult = await link2.link2(elementFactory, inputLibraries);
+        var linkResult = await link(elementFactory, inputLibraries);
         librariesLinked += cycle.libraries.length;
 
         resolutionBytes = linkResult.resolutionBytes;
diff --git a/pkg/analyzer/lib/src/error/must_call_super_verifier.dart b/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
index 0cb76fe..810758d 100644
--- a/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
+++ b/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
@@ -5,9 +5,9 @@
 import 'dart:collection';
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/ast/invokes_super_self.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
 
 class MustCallSuperVerifier {
@@ -133,9 +133,7 @@
 
   void _verifySuperIsCalled(MethodDeclaration node, String methodName,
       String? overriddenEnclosingName) {
-    _SuperCallVerifier verifier = _SuperCallVerifier(methodName);
-    node.accept(verifier);
-    if (!verifier.superIsCalled) {
+    if (!node.invokesSuperSelf) {
       // Overridable elements are always enclosed in named elements, so it is
       // safe to assume [overriddenEnclosingName] is non-`null`.
       _errorReporter.reportErrorForNode(
@@ -144,51 +142,3 @@
     return;
   }
 }
-
-/// Recursively visits an AST, looking for method invocations.
-class _SuperCallVerifier extends RecursiveAstVisitor<void> {
-  bool superIsCalled = false;
-
-  final String name;
-
-  _SuperCallVerifier(this.name);
-
-  @override
-  void visitAssignmentExpression(AssignmentExpression node) {
-    var lhs = node.leftHandSide;
-    if (lhs is PropertyAccess) {
-      if (lhs.target is SuperExpression && lhs.propertyName.name == name) {
-        superIsCalled = true;
-        return;
-      }
-    }
-    super.visitAssignmentExpression(node);
-  }
-
-  @override
-  void visitBinaryExpression(BinaryExpression node) {
-    if (node.leftOperand is SuperExpression && node.operator.lexeme == name) {
-      superIsCalled = true;
-      return;
-    }
-    super.visitBinaryExpression(node);
-  }
-
-  @override
-  void visitMethodInvocation(MethodInvocation node) {
-    if (node.target is SuperExpression && node.methodName.name == name) {
-      superIsCalled = true;
-      return;
-    }
-    super.visitMethodInvocation(node);
-  }
-
-  @override
-  void visitPropertyAccess(PropertyAccess node) {
-    if (node.target is SuperExpression && node.propertyName.name == name) {
-      superIsCalled = true;
-      return;
-    }
-    super.visitPropertyAccess(node);
-  }
-}
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 8cd98a7..b76283b 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -26,7 +26,7 @@
 var timerLinkingLinkingBundle = Stopwatch();
 
 /// Note that AST units and tokens of [inputLibraries] will be damaged.
-Future<LinkResult> link2(
+Future<LinkResult> link(
   LinkedElementFactory elementFactory,
   List<LinkInputLibrary> inputLibraries,
 ) async {
@@ -37,6 +37,15 @@
   );
 }
 
+/// Note that AST units and tokens of [inputLibraries] will be damaged.
+@Deprecated('Use link() instead')
+Future<LinkResult> link2(
+  LinkedElementFactory elementFactory,
+  List<LinkInputLibrary> inputLibraries,
+) async {
+  return link(elementFactory, inputLibraries);
+}
+
 class Linker {
   final LinkedElementFactory elementFactory;
 
diff --git a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
index 64302a5..082f9c0 100644
--- a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
@@ -304,6 +304,14 @@
 ''');
   }
 
+  test_class_field_withType_final_noConstConstructor() {
+    _assertSameSignature(r'''
+final int a = 1;
+''', r'''
+final int a = 2;
+''');
+  }
+
   test_class_field_withType_hasConstConstructor() {
     _assertSameSignature(r'''
 class C {
@@ -449,11 +457,80 @@
 ''');
   }
 
-  test_classLike_field_withType_final_noConstConstructor() {
+  test_classLike_method_body_block_invokesSuperSelf_false_differentName() {
     _assertSameSignature_classLike(r'''
-final int a = 1;
+void foo() {
+  super.bar();
+}
 ''', r'''
-final int a = 2;
+void foo() {
+  super.bar2();
+}
+''');
+  }
+
+  test_classLike_method_body_block_invokesSuperSelf_falseToTrue() {
+    _assertNotSameSignature_classLike(r'''
+void foo() {}
+''', r'''
+void foo() {
+  super.foo();
+}
+''');
+  }
+
+  test_classLike_method_body_block_invokesSuperSelf_trueToFalse_assignmentExpression() {
+    _assertNotSameSignature_classLike(r'''
+void foo() {
+  super.foo = 0;
+}
+''', r'''
+void foo() {}
+''');
+  }
+
+  test_classLike_method_body_block_invokesSuperSelf_trueToFalse_binaryExpression() {
+    _assertNotSameSignature_classLike(r'''
+int operator +() {
+  super + 2;
+  return 0;
+}
+''', r'''
+int operator +() {
+  return 0;
+}
+''');
+  }
+
+  test_classLike_method_body_block_invokesSuperSelf_trueToFalse_differentName() {
+    _assertNotSameSignature_classLike(r'''
+void foo() {
+  super.foo();
+}
+''', r'''
+void foo() {
+  super.bar();
+}
+''');
+  }
+
+  test_classLike_method_body_block_invokesSuperSelf_trueToFalse_methodInvocation() {
+    _assertNotSameSignature_classLike(r'''
+void foo() {
+  super.foo();
+}
+''', r'''
+void foo() {}
+''');
+  }
+
+  test_classLike_method_body_block_invokesSuperSelf_trueToFalse_propertyAccess() {
+    _assertNotSameSignature_classLike(r'''
+void foo() {
+  super.foo;
+}
+''', r'''
+void foo() {}
 ''');
   }
 
@@ -481,6 +558,14 @@
 ''');
   }
 
+  test_classLike_method_body_expression_invokesSuperSelf_trueToFalse_methodInvocation() {
+    _assertNotSameSignature_classLike(r'''
+void foo() => super.foo();
+''', r'''
+void foo() => 0;
+''');
+  }
+
   test_classLike_method_getter_body_block_to_empty() {
     _assertNotSameSignature_classLike(r'''
 int get foo {
@@ -619,6 +704,249 @@
 ''');
   }
 
+  test_enum_enumConstants_add() {
+    _assertNotSameSignature(r'''
+enum E {
+  v
+}
+''', r'''
+enum E {
+  v, v2
+}
+''');
+  }
+
+  test_enum_enumConstants_add_hasMethod() {
+    _assertNotSameSignature(r'''
+enum E {
+  v;
+  void foo() {}
+}
+''', r'''
+enum E {
+  v, v2;
+  void foo() {}
+}
+''');
+  }
+
+  test_enum_enumConstants_constructorArguments_add() {
+    _assertNotSameSignature(r'''
+enum E {
+  v;
+  E({int? a});
+}
+''', r'''
+enum E {
+  v(a: 0);
+  E({int? a});
+}
+''');
+  }
+
+  test_enum_enumConstants_constructorArguments_change() {
+    _assertNotSameSignature(r'''
+enum E {
+  v(0);
+  E(int a);
+}
+''', r'''
+enum E {
+  v(1);
+  E(int a);
+}
+''');
+  }
+
+  test_enum_enumConstants_constructorArguments_remove() {
+    _assertNotSameSignature(r'''
+enum E {
+  v(a: 0);
+  E({int? a});
+}
+''', r'''
+enum E {
+  v;
+  E({int? a});
+}
+''');
+  }
+
+  test_enum_enumConstants_remove() {
+    _assertNotSameSignature(r'''
+enum E {
+  v, v2
+}
+''', r'''
+enum E {
+  v
+}
+''');
+  }
+
+  test_enum_enumConstants_rename() {
+    _assertNotSameSignature(r'''
+enum E {
+  v
+}
+''', r'''
+enum E {
+  v2
+}
+''');
+  }
+
+  test_enum_field_withType_final() {
+    _assertNotSameSignature(r'''
+enum E {
+  v;
+  final int a = 1;
+}
+''', r'''
+enum E {
+  v;
+  final int a = 2;
+}
+''');
+  }
+
+  test_enum_implements_add() {
+    _assertNotSameSignature(r'''
+class A {}
+enum E {
+  v
+}
+''', r'''
+class A {}
+enum E implements A {
+  v
+}
+''');
+  }
+
+  test_enum_implements_change() {
+    _assertNotSameSignature(r'''
+class A {}
+class B {}
+enum E implements A {
+  v
+}
+''', r'''
+class A {}
+class B {}
+enum E implements B {
+  v
+}
+''');
+  }
+
+  test_enum_implements_remove() {
+    _assertNotSameSignature(r'''
+class A {}
+enum E implements A {
+  v
+}
+''', r'''
+class A {}
+enum E {
+  v
+}
+''');
+  }
+
+  test_enum_metadata_add() {
+    _assertNotSameSignature(r'''
+enum E {
+  v
+}
+''', r'''
+@a
+enum E {
+  v
+}
+''');
+  }
+
+  test_enum_typeParameters_add() {
+    _assertNotSameSignature(r'''
+enum E {
+  v
+}
+''', r'''
+enum E<T> {
+  v
+}
+''');
+  }
+
+  test_enum_typeParameters_remove() {
+    _assertNotSameSignature(r'''
+enum E<T> {
+  v
+}
+''', r'''
+enum E {
+  v
+}
+''');
+  }
+
+  test_enum_typeParameters_rename() {
+    _assertNotSameSignature(r'''
+enum E<T> {
+  v
+}
+''', r'''
+enum E<U> {
+  v
+}
+''');
+  }
+
+  test_enum_with_add() {
+    _assertNotSameSignature(r'''
+mixin M {}
+enum E {
+  v
+}
+''', r'''
+mixin M {}
+enum E with M {
+  v
+}
+''');
+  }
+
+  test_enum_with_change() {
+    _assertNotSameSignature(r'''
+mixin M1 {}
+mixin M2 {}
+enum E with M1 {
+  v
+}
+''', r'''
+mixin M1 {}
+mixin M2 {}
+enum E with M2 {
+  v
+}
+''');
+  }
+
+  test_enum_with_remove() {
+    _assertNotSameSignature(r'''
+mixin M {}
+enum E with M {
+  v
+}
+''', r'''
+mixin M {}
+enum E {
+  v
+}
+''');
+  }
+
   test_executable_annotation() {
     _assertNotSameSignature_executable(r'''
 void foo() {}
@@ -808,6 +1136,38 @@
 ''');
   }
 
+  test_extension_on() {
+    _assertNotSameSignature(r'''
+extension E on int {}
+''', r'''
+extension E on num {}
+''');
+  }
+
+  test_extension_typeParameter_add() {
+    _assertNotSameSignature(r'''
+extension E on int {}
+''', r'''
+extension E<T> on int {}
+''');
+  }
+
+  test_extension_typeParameter_remove() {
+    _assertNotSameSignature(r'''
+extension E<T> on int {}
+''', r'''
+extension E on int {}
+''');
+  }
+
+  test_extension_typeParameter_rename() {
+    _assertNotSameSignature(r'''
+extension E<T> on int {}
+''', r'''
+extension E<U> on int {}
+''');
+  }
+
   test_featureSet_add() async {
     _assertNotSameSignature(r'''
 class A {}
@@ -1064,6 +1424,16 @@
 ''', same: same);
 
     _assertSignature('''
+extension on int {
+$oldCode
+}
+''', '''
+extension on int {
+$newCode
+}
+''', same: same);
+
+    _assertSignature('''
 mixin M {
 $oldCode
 }
@@ -1072,6 +1442,18 @@
 $newCode
 }
 ''', same: same);
+
+    _assertSignature('''
+enum E {
+  v;
+$oldCode
+}
+''', '''
+enum E {
+  v;
+$newCode
+}
+''', same: same);
   }
 
   void _assertSignature_executable(String oldCode, String newCode,
diff --git a/pkg/analyzer/test/src/summary/elements_base.dart b/pkg/analyzer/test/src/summary/elements_base.dart
index fb702f8..f3d2095 100644
--- a/pkg/analyzer/test/src/summary/elements_base.dart
+++ b/pkg/analyzer/test/src/summary/elements_base.dart
@@ -102,7 +102,7 @@
       Reference.root(),
     );
 
-    var sdkLinkResult = await link2(elementFactory, inputLibraries);
+    var sdkLinkResult = await link(elementFactory, inputLibraries);
 
     return _sdkBundle = _SdkBundle(
       resolutionBytes: sdkLinkResult.resolutionBytes,
@@ -160,7 +160,7 @@
       ),
     );
 
-    var linkResult = await link2(elementFactory, inputLibraries);
+    var linkResult = await link(elementFactory, inputLibraries);
 
     if (!keepLinkingLibraries) {
       elementFactory.removeBundle(
diff --git a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
index a323582..c6fde24 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
@@ -185,7 +185,10 @@
 // Clobbers some registers with special meaning in Dart before re-entry, for
 // stress-testing. Not used on 32-bit Windows due to complications with Windows
 // "safeseh".
-#if defined(DART_TARGET_OS_WINDOWS) && defined(HOST_ARCH_IA32)
+// TODO(47824): Figure out how ARM/ARM64 syntax is different on Windows.
+#if defined(DART_TARGET_OS_WINDOWS) &&                                         \
+    (defined(HOST_ARCH_IA32) || defined(HOST_ARCH_ARM) ||                      \
+     defined(HOST_ARCH_ARM64))
 void ClobberAndCall(void (*fn)()) {
   fn();
 }
diff --git a/runtime/third_party/double-conversion/src/utils.h b/runtime/third_party/double-conversion/src/utils.h
index c419a6c..fe3e359 100644
--- a/runtime/third_party/double-conversion/src/utils.h
+++ b/runtime/third_party/double-conversion/src/utils.h
@@ -67,16 +67,22 @@
 // the output of the division with the expected result. (Inlining must be
 // disabled.)
 // On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
-#if defined(_M_X64) || defined(__x86_64__) || defined(__ARMEL__) ||            \
-    defined(__avr32__) || defined(__hppa__) || defined(__ia64__) ||            \
-    defined(__mips__) || defined(__powerpc__) || defined(__ppc__) ||           \
-    defined(__ppc64__) || defined(_POWER) || defined(_ARCH_PPC) ||             \
-    defined(_ARCH_PPC64) || defined(__sparc__) || defined(__sparc) ||          \
-    defined(__s390__) || defined(__SH4__) || defined(__alpha__) ||             \
-    defined(_MIPS_ARCH_MIPS32R2) || defined(__AARCH64EL__) ||                  \
-    defined(__aarch64__) || defined(__riscv)
+#if defined(_M_X64) || defined(__x86_64__) || \
+    defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
+    defined(__hppa__) || defined(__ia64__) || \
+    defined(__mips__) || \
+    defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
+    defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
+    defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
+    defined(__SH4__) || defined(__alpha__) || \
+    defined(_MIPS_ARCH_MIPS32R2) || \
+    defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \
+    defined(__riscv) || \
+    defined(__or1k__) || defined(__arc__) || \
+    defined(__EMSCRIPTEN__)
 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(__mc68000__)
+#elif defined(__mc68000__) || \
+    defined(__pnacl__) || defined(__native_client__)
 #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
 #if defined(_WIN32)
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 795745a..bca236c 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -271,7 +271,7 @@
   EmitType01(cond, o.type(), BIC, 1, rn, rd, o);
 }
 
-void Assembler::mvn(Register rd, Operand o, Condition cond) {
+void Assembler::mvn_(Register rd, Operand o, Condition cond) {
   EmitType01(cond, o.type(), MVN, 0, R0, rd, o);
 }
 
@@ -2779,7 +2779,7 @@
   if (Operand::CanHold(value, &o)) {
     mov(rd, o, cond);
   } else if (Operand::CanHold(~value, &o)) {
-    mvn(rd, o, cond);
+    mvn_(rd, o, cond);
   } else {
     LoadDecodableImmediate(rd, value, cond);
   }
@@ -3072,10 +3072,10 @@
   } else {
     ASSERT(rn != IP);
     if (Operand::CanHold(~value, &o)) {
-      mvn(IP, o, cond);
+      mvn_(IP, o, cond);
       add(rd, rn, Operand(IP), cond);
     } else if (Operand::CanHold(~(-value), &o)) {
-      mvn(IP, o, cond);
+      mvn_(IP, o, cond);
       sub(rd, rn, Operand(IP), cond);
     } else if (value > 0) {
       LoadDecodableImmediate(IP, value, cond);
@@ -3101,11 +3101,11 @@
   } else {
     ASSERT(rn != IP);
     if (Operand::CanHold(~value, &o)) {
-      mvn(IP, o, cond);
+      mvn_(IP, o, cond);
       adds(rd, rn, Operand(IP), cond);
     } else if (Operand::CanHold(~(-value), &o)) {
       ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
-      mvn(IP, o, cond);
+      mvn_(IP, o, cond);
       subs(rd, rn, Operand(IP), cond);
     } else {
       LoadDecodableImmediate(IP, value, cond);
@@ -3135,11 +3135,11 @@
   } else {
     ASSERT(rn != IP);
     if (Operand::CanHold(~value, &o)) {
-      mvn(IP, o, cond);
+      mvn_(IP, o, cond);
       subs(rd, rn, Operand(IP), cond);
     } else if (Operand::CanHold(~(-value), &o)) {
       ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
-      mvn(IP, o, cond);
+      mvn_(IP, o, cond);
       adds(rd, rn, Operand(IP), cond);
     } else {
       LoadDecodableImmediate(IP, value, cond);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 877820a..2f2f1fb 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -500,7 +500,7 @@
   void bic(Register rd, Register rn, Operand o, Condition cond = AL);
   void bics(Register rd, Register rn, Operand o, Condition cond = AL);
 
-  void mvn(Register rd, Operand o, Condition cond = AL);
+  void mvn_(Register rd, Operand o, Condition cond = AL);
   void mvns(Register rd, Operand o, Condition cond = AL);
 
   // Miscellaneous data-processing instructions.
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index b5ed07b..33fa8bb 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1586,7 +1586,9 @@
     }
   }
   void vmov(VRegister vd, VRegister vn) { vorr(vd, vn, vn); }
-  void mvn(Register rd, Register rm) { orn(rd, ZR, Operand(rm)); }
+  void mvn_(Register rd, Register rm) {
+    orn(rd, ZR, Operand(rm));
+  }
   void mvnw(Register rd, Register rm) { ornw(rd, ZR, Operand(rm)); }
   void neg(Register rd, Register rm) { sub(rd, ZR, Operand(rm)); }
   void negs(Register rd, Register rm, OperandSize sz = kEightBytes) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index cb29a3c..a95b7fe 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -3258,8 +3258,7 @@
 
 ASSEMBLER_TEST_RUN(Smaddl3, test) {
   typedef int64_t (*Int64Return)() DART_UNUSED;
-  EXPECT_EQ(0xffffl * 0xffffl,
-            EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+  EXPECT_EQ(0xfffe0001, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
   EXPECT_DISASSEMBLY(
       "movz r1, #0xffff\n"
       "movz r2, #0xffff\n"
diff --git a/runtime/vm/compiler/assembler/assembler_arm_test.cc b/runtime/vm/compiler/assembler/assembler_arm_test.cc
index 64db0ae..11adcf2 100644
--- a/runtime/vm/compiler/assembler/assembler_arm_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm_test.cc
@@ -75,7 +75,7 @@
 }
 
 ASSEMBLER_TEST_GENERATE(MoveNegated, assembler) {
-  __ mvn(R0, Operand(42));
+  __ mvn_(R0, Operand(42));
   __ Ret();
 }
 
@@ -988,7 +988,7 @@
   __ clz(R2, R2);
   __ cmp(R2, Operand(26));
   __ b(&error, NE);
-  __ mvn(R0, Operand(0));
+  __ mvn_(R0, Operand(0));
   __ clz(R1, R0);
   __ cmp(R1, Operand(0));
   __ b(&error, NE);
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index f92d297..fde11b60 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -5786,7 +5786,7 @@
       break;
     }
     case Token::kBIT_NOT:
-      __ mvn(result, compiler::Operand(value));
+      __ mvn_(result, compiler::Operand(value));
       // Remove inverted smi-tag.
       __ bic(result, result, compiler::Operand(kSmiTagMask));
       break;
@@ -7071,8 +7071,8 @@
 
   switch (op_kind()) {
     case Token::kBIT_NOT:
-      __ mvn(out_lo, compiler::Operand(left_lo));
-      __ mvn(out_hi, compiler::Operand(left_hi));
+      __ mvn_(out_lo, compiler::Operand(left_lo));
+      __ mvn_(out_hi, compiler::Operand(left_hi));
       break;
     case Token::kNEGATE:
       __ rsbs(out_lo, left_lo, compiler::Operand(0));
@@ -7143,7 +7143,7 @@
 
   ASSERT(op_kind() == Token::kBIT_NOT);
 
-  __ mvn(out, compiler::Operand(left));
+  __ mvn_(out, compiler::Operand(left));
 }
 
 LocationSummary* IntConverterInstr::MakeLocationSummary(Zone* zone,
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 3dbb6b0..7506894 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -4832,7 +4832,7 @@
       break;
     }
     case Token::kBIT_NOT:
-      __ mvn(result, value);
+      __ mvn_(result, value);
       // Remove inverted smi-tag.
       __ andi(result, result, compiler::Immediate(~kSmiTagMask));
       break;
@@ -6145,7 +6145,7 @@
   const Register out = locs()->out(0).reg();
   switch (op_kind()) {
     case Token::kBIT_NOT:
-      __ mvn(out, left);
+      __ mvn_(out, left);
       break;
     case Token::kNEGATE:
       __ sub(out, ZR, compiler::Operand(left));
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index ed64ffd..0034a52 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -52,6 +52,101 @@
   __ Bind(&done);
 }
 
+// In TSAN mode the runtime will throw an exception using an intermediary
+// longjmp() call to unwind the C frames in a way that TSAN can understand.
+//
+// This wrapper will setup a [jmp_buf] on the stack and initialize it to be a
+// target for a possible longjmp(). In the exceptional case we'll forward
+// control of execution to the usual JumpToFrame stub.
+//
+// In non-TSAN mode this will do nothing and the runtime will call the
+// JumpToFrame stub directly.
+//
+// The callback [fun] may be invoked with a modified [RSP] due to allocating
+// a [jmp_buf] allocating structure on the stack (as well as the saved old
+// [Thread::tsan_utils_->setjmp_buffer_]).
+static void WithExceptionCatchingTrampoline(Assembler* assembler,
+                                            std::function<void()> fun) {
+#if defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
+  const Register kTsanUtilsReg = R3;
+
+  // Reserve space for arguments and align frame before entering C++ world.
+  const intptr_t kJumpBufferSize = sizeof(jmp_buf);
+  // Save & Restore the volatile CPU registers across the setjmp() call.
+  const RegisterSet volatile_registers(
+      kAbiVolatileCpuRegs & ~(1 << R0) & ~(1 << SP),
+      /*fpu_registers=*/0);
+
+  const Register kSavedRspReg = R20;
+  COMPILE_ASSERT(IsCalleeSavedRegister(kSavedRspReg));
+  // We rely on THR being preserved across the setjmp() call.
+  COMPILE_ASSERT(IsCalleeSavedRegister(THR));
+
+  Label do_native_call;
+
+  // Save old jmp_buf.
+  __ ldr(kTsanUtilsReg, Address(THR, target::Thread::tsan_utils_offset()));
+  __ ldr(TMP,
+         Address(kTsanUtilsReg, target::TsanUtils::setjmp_buffer_offset()));
+  __ Push(TMP);
+
+  // Allocate jmp_buf struct on stack & remember pointer to it on the
+  // [Thread::tsan_utils_->setjmp_buffer] (which exceptions.cc will longjmp()
+  // to)
+  __ AddImmediate(SP, -kJumpBufferSize);
+  __ str(SP, Address(kTsanUtilsReg, target::TsanUtils::setjmp_buffer_offset()));
+
+  // Call setjmp() with a pointer to the allocated jmp_buf struct.
+  __ MoveRegister(R0, SP);
+  __ PushRegisters(volatile_registers);
+  __ EnterCFrame(0);
+  __ mov(R25, CSP);
+  __ mov(CSP, SP);
+  __ ldr(kTsanUtilsReg, Address(THR, target::Thread::tsan_utils_offset()));
+  __ CallCFunction(
+      Address(kTsanUtilsReg, target::TsanUtils::setjmp_function_offset()));
+  __ mov(SP, CSP);
+  __ mov(CSP, R25);
+  __ LeaveCFrame();
+  __ PopRegisters(volatile_registers);
+
+  // We are the target of a longjmp() iff setjmp() returns non-0.
+  __ cbz(&do_native_call, R0);
+
+  // We are the target of a longjmp: Cleanup the stack and tail-call the
+  // JumpToFrame stub which will take care of unwinding the stack and hand
+  // execution to the catch entry.
+  __ AddImmediate(SP, kJumpBufferSize);
+  __ ldr(kTsanUtilsReg, Address(THR, target::Thread::tsan_utils_offset()));
+  __ Pop(TMP);
+  __ str(TMP,
+         Address(kTsanUtilsReg, target::TsanUtils::setjmp_buffer_offset()));
+
+  __ ldr(R0, Address(kTsanUtilsReg, target::TsanUtils::exception_pc_offset()));
+  __ ldr(R1, Address(kTsanUtilsReg, target::TsanUtils::exception_sp_offset()));
+  __ ldr(R2, Address(kTsanUtilsReg, target::TsanUtils::exception_fp_offset()));
+  __ MoveRegister(R3, THR);
+  __ Jump(Address(THR, target::Thread::jump_to_frame_entry_point_offset()));
+
+  // We leave the created [jump_buf] structure on the stack as well as the
+  // pushed old [Thread::tsan_utils_->setjmp_buffer_].
+  __ Bind(&do_native_call);
+  __ MoveRegister(kSavedRspReg, SP);
+#endif  // defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
+
+  fun();
+
+#if defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
+  __ MoveRegister(SP, kSavedRspReg);
+  __ AddImmediate(SP, kJumpBufferSize);
+  const Register kTsanUtilsReg2 = kSavedRspReg;
+  __ ldr(kTsanUtilsReg2, Address(THR, target::Thread::tsan_utils_offset()));
+  __ Pop(TMP);
+  __ str(TMP,
+         Address(kTsanUtilsReg2, target::TsanUtils::setjmp_buffer_offset()));
+#endif  // defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
+}
+
 // Input parameters:
 //   LR : return address.
 //   SP : address of last argument in argument array.
@@ -93,73 +188,75 @@
   // Mark that the thread is executing VM code.
   __ StoreToOffset(R5, THR, target::Thread::vm_tag_offset());
 
-  // Reserve space for arguments and align frame before entering C++ world.
-  // target::NativeArguments are passed in registers.
-  __ Comment("align stack");
-  // Reserve space for arguments.
-  ASSERT(target::NativeArguments::StructSize() == 4 * target::kWordSize);
-  __ ReserveAlignedFrameSpace(target::NativeArguments::StructSize());
+  WithExceptionCatchingTrampoline(assembler, [&]() {
+    // Reserve space for arguments and align frame before entering C++ world.
+    // target::NativeArguments are passed in registers.
+    __ Comment("align stack");
+    // Reserve space for arguments.
+    ASSERT(target::NativeArguments::StructSize() == 4 * target::kWordSize);
+    __ ReserveAlignedFrameSpace(target::NativeArguments::StructSize());
 
-  // Pass target::NativeArguments structure by value and call runtime.
-  // Registers R0, R1, R2, and R3 are used.
+    // Pass target::NativeArguments structure by value and call runtime.
+    // Registers R0, R1, R2, and R3 are used.
 
-  ASSERT(thread_offset == 0 * target::kWordSize);
-  // Set thread in NativeArgs.
-  __ mov(R0, THR);
+    ASSERT(thread_offset == 0 * target::kWordSize);
+    // Set thread in NativeArgs.
+    __ mov(R0, THR);
 
-  // There are no runtime calls to closures, so we do not need to set the tag
-  // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
-  ASSERT(argc_tag_offset == 1 * target::kWordSize);
-  __ mov(R1, R4);  // Set argc in target::NativeArguments.
+    // There are no runtime calls to closures, so we do not need to set the tag
+    // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
+    ASSERT(argc_tag_offset == 1 * target::kWordSize);
+    __ mov(R1, R4);  // Set argc in target::NativeArguments.
 
-  ASSERT(argv_offset == 2 * target::kWordSize);
-  __ add(R2, ZR, Operand(R4, LSL, 3));
-  __ add(R2, FP, Operand(R2));  // Compute argv.
-  // Set argv in target::NativeArguments.
-  __ AddImmediate(R2,
-                  target::frame_layout.param_end_from_fp * target::kWordSize);
+    ASSERT(argv_offset == 2 * target::kWordSize);
+    __ add(R2, ZR, Operand(R4, LSL, 3));
+    __ add(R2, FP, Operand(R2));  // Compute argv.
+    // Set argv in target::NativeArguments.
+    __ AddImmediate(R2,
+                    target::frame_layout.param_end_from_fp * target::kWordSize);
 
-  ASSERT(retval_offset == 3 * target::kWordSize);
-  __ AddImmediate(R3, R2, target::kWordSize);
+    ASSERT(retval_offset == 3 * target::kWordSize);
+    __ AddImmediate(R3, R2, target::kWordSize);
 
-  __ StoreToOffset(R0, SP, thread_offset);
-  __ StoreToOffset(R1, SP, argc_tag_offset);
-  __ StoreToOffset(R2, SP, argv_offset);
-  __ StoreToOffset(R3, SP, retval_offset);
-  __ mov(R0, SP);  // Pass the pointer to the target::NativeArguments.
+    __ StoreToOffset(R0, SP, thread_offset);
+    __ StoreToOffset(R1, SP, argc_tag_offset);
+    __ StoreToOffset(R2, SP, argv_offset);
+    __ StoreToOffset(R3, SP, retval_offset);
+    __ mov(R0, SP);  // Pass the pointer to the target::NativeArguments.
 
-  // We are entering runtime code, so the C stack pointer must be restored from
-  // the stack limit to the top of the stack. We cache the stack limit address
-  // in a callee-saved register.
-  __ mov(R25, CSP);
-  __ mov(CSP, SP);
+    // We are entering runtime code, so the C stack pointer must be restored
+    // from the stack limit to the top of the stack. We cache the stack limit
+    // address in a callee-saved register.
+    __ mov(R25, CSP);
+    __ mov(CSP, SP);
 
-  __ blr(R5);
-  __ Comment("CallToRuntimeStub return");
+    __ blr(R5);
+    __ Comment("CallToRuntimeStub return");
 
-  // Restore SP and CSP.
-  __ mov(SP, CSP);
-  __ mov(CSP, R25);
+    // Restore SP and CSP.
+    __ mov(SP, CSP);
+    __ mov(CSP, R25);
 
-  // Refresh pinned registers values (inc. write barrier mask and null object).
-  __ RestorePinnedRegisters();
+    // Refresh pinned registers (write barrier mask, null, dispatch table, etc).
+    __ RestorePinnedRegisters();
 
-  // Retval is next to 1st argument.
-  // Mark that the thread is executing Dart code.
-  __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
+    // Retval is next to 1st argument.
+    // Mark that the thread is executing Dart code.
+    __ LoadImmediate(R2, VMTag::kDartTagId);
+    __ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
 
-  // Mark that the thread has not exited generated Dart code.
-  __ StoreToOffset(ZR, THR, target::Thread::exit_through_ffi_offset());
+    // Mark that the thread has not exited generated Dart code.
+    __ StoreToOffset(ZR, THR, target::Thread::exit_through_ffi_offset());
 
-  // Reset exit frame information in Isolate's mutator thread structure.
-  __ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
+    // Reset exit frame information in Isolate's mutator thread structure.
+    __ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
 
-  // Restore the global object pool after returning from runtime (old space is
-  // moving, so the GOP could have been relocated).
-  if (FLAG_precompiled_mode) {
-    __ SetupGlobalPoolAndDispatchTable();
-  }
+    // Restore the global object pool after returning from runtime (old space is
+    // moving, so the GOP could have been relocated).
+    if (FLAG_precompiled_mode) {
+      __ SetupGlobalPoolAndDispatchTable();
+    }
+  });
 
   __ LeaveStubFrame();
 
@@ -678,73 +775,76 @@
   // Mark that the thread is executing native code.
   __ StoreToOffset(R5, THR, target::Thread::vm_tag_offset());
 
-  // Reserve space for the native arguments structure passed on the stack (the
-  // outgoing pointer parameter to the native arguments structure is passed in
-  // R0) and align frame before entering the C++ world.
-  __ ReserveAlignedFrameSpace(target::NativeArguments::StructSize());
+  WithExceptionCatchingTrampoline(assembler, [&]() {
+    // Reserve space for the native arguments structure passed on the stack (the
+    // outgoing pointer parameter to the native arguments structure is passed in
+    // R0) and align frame before entering the C++ world.
+    __ ReserveAlignedFrameSpace(target::NativeArguments::StructSize());
 
-  // Initialize target::NativeArguments structure and call native function.
-  // Registers R0, R1, R2, and R3 are used.
+    // Initialize target::NativeArguments structure and call native function.
+    // Registers R0, R1, R2, and R3 are used.
 
-  ASSERT(thread_offset == 0 * target::kWordSize);
-  // Set thread in NativeArgs.
-  __ mov(R0, THR);
+    ASSERT(thread_offset == 0 * target::kWordSize);
+    // Set thread in NativeArgs.
+    __ mov(R0, THR);
 
-  // There are no native calls to closures, so we do not need to set the tag
-  // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
-  ASSERT(argc_tag_offset == 1 * target::kWordSize);
-  // Set argc in target::NativeArguments: R1 already contains argc.
+    // There are no native calls to closures, so we do not need to set the tag
+    // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
+    ASSERT(argc_tag_offset == 1 * target::kWordSize);
+    // Set argc in target::NativeArguments: R1 already contains argc.
 
-  ASSERT(argv_offset == 2 * target::kWordSize);
-  // Set argv in target::NativeArguments: R2 already contains argv.
+    ASSERT(argv_offset == 2 * target::kWordSize);
+    // Set argv in target::NativeArguments: R2 already contains argv.
 
-  // Set retval in NativeArgs.
-  ASSERT(retval_offset == 3 * target::kWordSize);
-  __ AddImmediate(
-      R3, FP, (target::frame_layout.param_end_from_fp + 1) * target::kWordSize);
+    // Set retval in NativeArgs.
+    ASSERT(retval_offset == 3 * target::kWordSize);
+    __ AddImmediate(
+        R3, FP,
+        (target::frame_layout.param_end_from_fp + 1) * target::kWordSize);
 
-  // Passing the structure by value as in runtime calls would require changing
-  // Dart API for native functions.
-  // For now, space is reserved on the stack and we pass a pointer to it.
-  __ StoreToOffset(R0, SP, thread_offset);
-  __ StoreToOffset(R1, SP, argc_tag_offset);
-  __ StoreToOffset(R2, SP, argv_offset);
-  __ StoreToOffset(R3, SP, retval_offset);
-  __ mov(R0, SP);  // Pass the pointer to the target::NativeArguments.
+    // Passing the structure by value as in runtime calls would require changing
+    // Dart API for native functions.
+    // For now, space is reserved on the stack and we pass a pointer to it.
+    __ StoreToOffset(R0, SP, thread_offset);
+    __ StoreToOffset(R1, SP, argc_tag_offset);
+    __ StoreToOffset(R2, SP, argv_offset);
+    __ StoreToOffset(R3, SP, retval_offset);
+    __ mov(R0, SP);  // Pass the pointer to the target::NativeArguments.
 
-  // We are entering runtime code, so the C stack pointer must be restored from
-  // the stack limit to the top of the stack. We cache the stack limit address
-  // in the Dart SP register, which is callee-saved in the C ABI.
-  __ mov(R25, CSP);
-  __ mov(CSP, SP);
+    // We are entering runtime code, so the C stack pointer must be restored
+    // from the stack limit to the top of the stack. We cache the stack limit
+    // address in the Dart SP register, which is callee-saved in the C ABI.
+    __ mov(R25, CSP);
+    __ mov(CSP, SP);
 
-  __ mov(R1, R5);  // Pass the function entrypoint to call.
+    __ mov(R1, R5);  // Pass the function entrypoint to call.
 
-  // Call native function invocation wrapper or redirection via simulator.
-  __ Call(wrapper);
+    // Call native function invocation wrapper or redirection via simulator.
+    __ Call(wrapper);
 
-  // Restore SP and CSP.
-  __ mov(SP, CSP);
-  __ mov(CSP, R25);
+    // Restore SP and CSP.
+    __ mov(SP, CSP);
+    __ mov(CSP, R25);
 
-  // Refresh pinned registers values (inc. write barrier mask and null object).
-  __ RestorePinnedRegisters();
+    // Refresh pinned registers (write barrier mask, null, dispatch table, etc).
+    __ RestorePinnedRegisters();
 
-  // Mark that the thread is executing Dart code.
-  __ LoadImmediate(R2, VMTag::kDartTagId);
-  __ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
+    // Mark that the thread is executing Dart code.
+    __ LoadImmediate(R2, VMTag::kDartTagId);
+    __ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
 
-  // Mark that the thread has not exited generated Dart code.
-  __ StoreToOffset(ZR, THR, target::Thread::exit_through_ffi_offset());
+    // Mark that the thread has not exited generated Dart code.
+    __ StoreToOffset(ZR, THR, target::Thread::exit_through_ffi_offset());
 
-  // Reset exit frame information in Isolate's mutator thread structure.
-  __ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
+    // Reset exit frame information in Isolate's mutator thread structure.
+    __ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
 
-  // Restore the global object pool after returning from runtime (old space is
-  // moving, so the GOP could have been relocated).
-  if (FLAG_precompiled_mode) {
-    __ SetupGlobalPoolAndDispatchTable();
-  }
+    // Restore the global object pool after returning from runtime (old space is
+    // moving, so the GOP could have been relocated).
+    if (FLAG_precompiled_mode) {
+      __ SetupGlobalPoolAndDispatchTable();
+    }
+  });
 
   __ LeaveStubFrame();
   __ ret();
@@ -1393,7 +1493,7 @@
     __ mov(THR, R3);
   }
 
-  // Refresh pinned registers values (inc. write barrier mask and null object).
+  // Refresh pinned registers (write barrier mask, null, dispatch table, etc).
   __ RestorePinnedRegisters();
 
   // Save the current VMTag on the stack.
@@ -3125,7 +3225,7 @@
                                  /*ignore_unwind_in_progress=*/true);
   __ Bind(&exit_through_non_ffi);
 
-  // Refresh pinned registers values (inc. write barrier mask and null object).
+  // Refresh pinned registers (write barrier mask, null, dispatch table, etc).
   __ RestorePinnedRegisters();
   // Set the tag.
   __ LoadImmediate(R2, VMTag::kDartTagId);
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 998fac5..c817ad4 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -70,7 +70,7 @@
 // [Thread::tsan_utils_->setjmp_buffer_]).
 static void WithExceptionCatchingTrampoline(Assembler* assembler,
                                             std::function<void()> fun) {
-#if defined(USING_THREAD_SANITIZER)
+#if defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
   const Register kTsanUtilsReg = RAX;
 
   // Reserve space for arguments and align frame before entering C++ world.
@@ -138,17 +138,17 @@
   // pushed old [Thread::tsan_utils_->setjmp_buffer_].
   __ Bind(&do_native_call);
   __ MoveRegister(kSavedRspReg, RSP);
-#endif  // defined(USING_THREAD_SANITIZER)
+#endif  // defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
 
   fun();
 
-#if defined(USING_THREAD_SANITIZER)
+#if defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
   __ MoveRegister(RSP, kSavedRspReg);
   __ AddImmediate(RSP, Immediate(kJumpBufferSize));
   const Register kTsanUtilsReg2 = kSavedRspReg;
   __ movq(kTsanUtilsReg2, Address(THR, target::Thread::tsan_utils_offset()));
   __ popq(Address(kTsanUtilsReg2, target::TsanUtils::setjmp_buffer_offset()));
-#endif  // defined(USING_THREAD_SANITIZER)
+#endif  // defined(USING_THREAD_SANITIZER) && !defined(USING_SIMULATOR)
 }
 
 // Input parameters:
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index b09a94a..94fdda6 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -395,6 +395,9 @@
 // C++ ABI call registers.
 const RegList kAbiArgumentCpuRegs =
     R(R0) | R(R1) | R(R2) | R(R3) | R(R4) | R(R5) | R(R6) | R(R7);
+const RegList kAbiVolatileCpuRegs =
+    kAbiArgumentCpuRegs | R(R8) | R(R9) | R(R10) | R(R11) | R(R12) | R(R13) |
+    R(R14) | R(R15) | R(R16) | R(R17);
 #if defined(DART_TARGET_OS_FUCHSIA)
 // We rely on R18 not being touched by Dart generated assembly or stubs at all.
 // We rely on that any calls into C++ also preserve R18.
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index b18056a..eef1084 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -14,15 +14,12 @@
 #include "vm/object.h"
 #include "vm/simulator.h"
 
-#if defined(DART_HOST_OS_IOS)
+#if !defined(TARGET_HOST_MISMATCH)
+#if defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_IOS)
 #include <libkern/OSCacheControl.h>
 #elif defined(DART_HOST_OS_WINDOWS)
 #include <processthreadsapi.h>
 #endif
-
-#if !defined(TARGET_HOST_MISMATCH)
-#include <sys/syscall.h> /* NOLINT */
-#include <unistd.h>      /* NOLINT */
 #endif
 
 // ARM version differences.
diff --git a/runtime/vm/cpu_arm64.cc b/runtime/vm/cpu_arm64.cc
index 1ae9f0d..10827ba 100644
--- a/runtime/vm/cpu_arm64.cc
+++ b/runtime/vm/cpu_arm64.cc
@@ -12,19 +12,14 @@
 #include "vm/simulator.h"
 
 #if !defined(USING_SIMULATOR)
-#if !defined(DART_HOST_OS_FUCHSIA)
-#include <sys/syscall.h>
-#else
+#if defined(DART_HOST_OS_FUCHSIA)
 #include <zircon/syscalls.h>
-#endif
-#include <unistd.h>
-#endif
-
-#if defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_IOS)
+#elif defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_IOS)
 #include <libkern/OSCacheControl.h>
 #elif defined(DART_HOST_OS_WINDOWS)
 #include <processthreadsapi.h>
 #endif
+#endif
 
 namespace dart {
 
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index 1a3d6c0..c564a48 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -180,12 +180,9 @@
   __asm { mov fp, ebp}                                                         \
   ;  // NOLINT
 // clang-format on
-#elif defined(HOST_ARCH_X64)
-// We don't have the asm equivalent to get at the frame pointer on
-// windows x64, return the stack pointer instead.
-#define COPY_FP_REGISTER(fp) fp = OSThread::GetCurrentStackPointer();
 #else
-#error Unknown host architecture.
+// Inline assembly is only available on x86; return the stack pointer instead.
+#define COPY_FP_REGISTER(fp) fp = OSThread::GetCurrentStackPointer();
 #endif
 
 #else  // !defined(DART_HOST_OS_WINDOWS))
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d8ae4af..fb9bb9d 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -416,6 +416,14 @@
   uword pc = static_cast<uword>(ctx->Rip);
   uword fp = static_cast<uword>(ctx->Rbp);
   uword sp = static_cast<uword>(ctx->Rsp);
+#elif defined(HOST_ARCH_ARM)
+  uword pc = static_cast<uword>(ctx->Pc);
+  uword fp = static_cast<uword>(ctx->R11);
+  uword sp = static_cast<uword>(ctx->Sp);
+#elif defined(HOST_ARCH_ARM64)
+  uword pc = static_cast<uword>(ctx->Pc);
+  uword fp = static_cast<uword>(ctx->Fp);
+  uword sp = static_cast<uword>(ctx->Sp);
 #else
 #error Unsupported architecture.
 #endif
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index 3db5023..a7cdef7 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -26,7 +26,8 @@
 #if defined(HOST_ARCH_IA32)
     // On IA32, CONTEXT_CONTROL includes Eip, Ebp, and Esp.
     context.ContextFlags = CONTEXT_CONTROL;
-#elif defined(HOST_ARCH_X64)
+#elif defined(HOST_ARCH_X64) || defined(HOST_ARCH_ARM) ||                      \
+    defined(HOST_ARCH_ARM64)
     // On X64, CONTEXT_CONTROL includes Rip and Rsp. Rbp is classified
     // as an "integer" register.
     context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
@@ -44,6 +45,16 @@
       state->fp = static_cast<uintptr_t>(context.Rbp);
       state->csp = static_cast<uintptr_t>(context.Rsp);
       state->dsp = static_cast<uintptr_t>(context.Rsp);
+#elif defined(HOST_ARCH_ARM)
+      state->pc = static_cast<uintptr_t>(context.Pc);
+      state->fp = static_cast<uintptr_t>(context.R11);
+      state->csp = static_cast<uintptr_t>(context.Sp);
+      state->dsp = static_cast<uintptr_t>(context.Sp);
+#elif defined(HOST_ARCH_ARM64)
+      state->pc = static_cast<uintptr_t>(context.Pc);
+      state->fp = static_cast<uintptr_t>(context.Fp);
+      state->csp = static_cast<uintptr_t>(context.Sp);
+      state->dsp = static_cast<uintptr_t>(context.X15);
 #else
 #error Unsupported architecture.
 #endif
diff --git a/tools/VERSION b/tools/VERSION
index db9b0e4..3153c6e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 283
+PRERELEASE 284
 PRERELEASE_PATCH 0
\ No newline at end of file