Version 2.15.0-154.0.dev

Merge commit 'cac3e81f27ad8c341e77263e360e50b0217a73f6' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/update_sdk_constraints.dart b/pkg/analysis_server/lib/src/services/correction/dart/update_sdk_constraints.dart
index 4cab9d2..2ade5a5 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/update_sdk_constraints.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/update_sdk_constraints.dart
@@ -72,6 +72,11 @@
   }
 
   /// Return an instance of this class that will update the SDK constraints to
+  /// '2.14.0'. Used as a tear-off in `FixProcessor`.
+  static UpdateSdkConstraints version_2_14_0() =>
+      UpdateSdkConstraints('2.14.0');
+
+  /// Return an instance of this class that will update the SDK constraints to
   /// '2.1.0'. Used as a tear-off in `FixProcessor`.
   static UpdateSdkConstraints version_2_1_0() => UpdateSdkConstraints('2.1.0');
 
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 2964ba0..598cd1a 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1158,7 +1158,7 @@
       UpdateSdkConstraints.version_2_6_0,
     ],
     HintCode.SDK_VERSION_GT_GT_GT_OPERATOR: [
-      UpdateSdkConstraints.version_2_2_2,
+      UpdateSdkConstraints.version_2_14_0,
     ],
     HintCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT: [
       UpdateSdkConstraints.version_2_2_2,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/update_sdk_constraints_test.dart b/pkg/analysis_server/test/src/services/correction/fix/update_sdk_constraints_test.dart
index c5c8763..07037a4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/update_sdk_constraints_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/update_sdk_constraints_test.dart
@@ -70,7 +70,7 @@
 class C {
   C operator >>>(C other) => this;
 }
-''', to: '^2.2.2');
+''', to: '^2.14.0');
   }
 
   Future<void> test_isInConstContext() async {
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 3e16e13..5b6574a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -1501,7 +1501,7 @@
 
     var libraryContext = _libraryContext;
     libraryContext ??= _libraryContext = LibraryContext(
-      testView: _testView.libraryContext,
+      testView: _testView.libraryContextTestView,
       session: currentSession,
       logger: _logger,
       byteStore: _byteStore,
@@ -2054,7 +2054,8 @@
 @visibleForTesting
 class AnalysisDriverTestView {
   final AnalysisDriver driver;
-  final LibraryContextTestView libraryContext = LibraryContextTestView();
+  final LibraryContextTestView libraryContextTestView =
+      LibraryContextTestView();
 
   int numOfAnalyzedLibraries = 0;
 
@@ -2062,8 +2063,7 @@
 
   FileTracker get fileTracker => driver._fileTracker;
 
-  /// TODO(scheglov) Rename this, and [libraryContext].
-  LibraryContext? get libraryContext2 => driver._libraryContext;
+  LibraryContext? get libraryContext => driver._libraryContext;
 
   Map<String, ResolvedUnitResult> get priorityResults {
     return driver._priorityResults;
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index af7d2b2..f881032 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -2489,19 +2489,19 @@
   // #### Description
   //
   // The analyzer produces this diagnostic when the operator `>>>` is used in
-  // code that has an SDK constraint whose lower bound is less than 2.X.0. This
+  // code that has an SDK constraint whose lower bound is less than 2.14.0. This
   // operator wasn't supported in earlier versions, so this code won't be able
   // to run against earlier versions of the SDK.
   //
   // #### Examples
   //
   // Here's an example of a pubspec that defines an SDK constraint with a lower
-  // bound of less than 2.X.0:
+  // bound of less than 2.14.0:
   //
   // ```yaml
   // %uri="pubspec.yaml"
   // environment:
-  //  sdk: '>=2.0.0 <2.4.0'
+  //  sdk: '>=2.0.0 <2.15.0'
   // ```
   //
   // In the package that has that pubspec, code like the following produces this
@@ -2518,7 +2518,7 @@
   //
   // ```yaml
   // environment:
-  //   sdk: '>=2.3.2 <2.4.0'
+  //   sdk: '>=2.14.0 <2.15.0'
   // ```
   //
   // If you need to support older versions of the SDK, then rewrite the code to
@@ -2537,7 +2537,7 @@
   // ```
   static const HintCode SDK_VERSION_GT_GT_GT_OPERATOR = HintCode(
       'SDK_VERSION_GT_GT_GT_OPERATOR',
-      "The operator '>>>' wasn't supported until version 2.3.2, but this code "
+      "The operator '>>>' wasn't supported until version 2.14.0, but this code "
           "is required to be able to run on earlier versions.",
       correction: "Try updating the SDK constraints.");
 
diff --git a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
index e0c34fd..f6df998 100644
--- a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
+++ b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
@@ -33,6 +33,10 @@
   /// field.
   bool? _checkConstantUpdate2018;
 
+  /// A cached flag indicating whether references to the triple-shift features
+  /// need to be checked. Use [checkTripleShift] to access this field.
+  bool? _checkTripleShift;
+
   /// A cached flag indicating whether uses of extension method features need to
   /// be checked. Use [checkExtensionMethods] to access this field.
   bool? _checkExtensionMethods;
@@ -63,6 +67,10 @@
   SdkConstraintVerifier(this._errorReporter, this._containingLibrary,
       this._typeProvider, this._versionConstraint);
 
+  /// Return a range covering every version up to, but not including, 2.14.0.
+  VersionRange get before_2_14_0 =>
+      VersionRange(max: Version.parse('2.14.0'), includeMax: false);
+
   /// Return a range covering every version up to, but not including, 2.1.0.
   VersionRange get before_2_1_0 =>
       VersionRange(max: Version.parse('2.1.0'), includeMax: false);
@@ -105,6 +113,11 @@
   bool get checkSetLiterals =>
       _checkSetLiterals ??= !before_2_2_0.intersect(_versionConstraint).isEmpty;
 
+  /// Return `true` if references to the constant-update-2018 features need to
+  /// be checked.
+  bool get checkTripleShift => _checkTripleShift ??=
+      !before_2_14_0.intersect(_versionConstraint).isEmpty;
+
   /// Return `true` if references to the ui-as-code features (control flow and
   /// spread collections) need to be checked.
   bool get checkUiAsCode =>
@@ -121,35 +134,37 @@
 
   @override
   void visitBinaryExpression(BinaryExpression node) {
-    if (checkConstantUpdate2018) {
+    if (checkTripleShift) {
       TokenType operatorType = node.operator.type;
       if (operatorType == TokenType.GT_GT_GT) {
         _errorReporter.reportErrorForToken(
             HintCode.SDK_VERSION_GT_GT_GT_OPERATOR, node.operator);
-      } else if ((operatorType == TokenType.AMPERSAND ||
-              operatorType == TokenType.BAR ||
-              operatorType == TokenType.CARET) &&
-          node.inConstantContext) {
-        if (node.leftOperand.typeOrThrow.isDartCoreBool) {
-          _errorReporter.reportErrorForToken(
-              HintCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
-              node.operator,
-              [node.operator.lexeme]);
-        }
-      } else if (operatorType == TokenType.EQ_EQ && node.inConstantContext) {
-        bool primitive(Expression node) {
-          DartType type = node.typeOrThrow;
-          return type.isDartCoreBool ||
-              type.isDartCoreDouble ||
-              type.isDartCoreInt ||
-              type.isDartCoreNull ||
-              type.isDartCoreString;
-        }
+      } else if (checkConstantUpdate2018) {
+        if ((operatorType == TokenType.AMPERSAND ||
+                operatorType == TokenType.BAR ||
+                operatorType == TokenType.CARET) &&
+            node.inConstantContext) {
+          if (node.leftOperand.typeOrThrow.isDartCoreBool) {
+            _errorReporter.reportErrorForToken(
+                HintCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
+                node.operator,
+                [node.operator.lexeme]);
+          }
+        } else if (operatorType == TokenType.EQ_EQ && node.inConstantContext) {
+          bool primitive(Expression node) {
+            DartType type = node.typeOrThrow;
+            return type.isDartCoreBool ||
+                type.isDartCoreDouble ||
+                type.isDartCoreInt ||
+                type.isDartCoreNull ||
+                type.isDartCoreString;
+          }
 
-        if (!primitive(node.leftOperand) || !primitive(node.rightOperand)) {
-          _errorReporter.reportErrorForToken(
-              HintCode.SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT,
-              node.operator);
+          if (!primitive(node.leftOperand) || !primitive(node.rightOperand)) {
+            _errorReporter.reportErrorForToken(
+                HintCode.SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT,
+                node.operator);
+          }
         }
       }
     }
@@ -210,7 +225,7 @@
 
   @override
   void visitMethodDeclaration(MethodDeclaration node) {
-    if (checkConstantUpdate2018 && node.isOperator && node.name.name == '>>>') {
+    if (checkTripleShift && node.isOperator && node.name.name == '>>>') {
       _errorReporter.reportErrorForNode(
           HintCode.SDK_VERSION_GT_GT_GT_OPERATOR, node.name);
     }
diff --git a/pkg/analyzer/lib/src/workspace/bazel_watcher.dart b/pkg/analyzer/lib/src/workspace/bazel_watcher.dart
index cd56312..b3f09ec 100644
--- a/pkg/analyzer/lib/src/workspace/bazel_watcher.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel_watcher.dart
@@ -10,7 +10,6 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/service.dart';
-import 'package:pedantic/pedantic.dart';
 import 'package:watcher/watcher.dart';
 
 Future<void> _isolateMain(SendPort sendPort) async {
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 3b0dae7..dd5d48d 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -20,7 +20,6 @@
   source_span: ^1.8.0
   watcher: ^1.0.0
   yaml: ^3.0.0
-  pedantic: ^1.10.0
 dev_dependencies:
   analyzer_utilities:
     path: ../analyzer_utilities
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
index e6f424c..58450c4 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
@@ -22,7 +22,7 @@
 
   List<Set<String>> get _linkedCycles {
     var driver = driverFor(testFilePath);
-    return driver.test.libraryContext.linkedCycles;
+    return driver.test.libraryContextTestView.linkedCycles;
   }
 
   test_change_factoryConstructor_addEqNothing() async {
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index f2b9cde..ab00fb1 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -3473,7 +3473,7 @@
   }
 
   Set<String> get loadedLibraryUriSet {
-    var elementFactory = this.test.libraryContext2!.elementFactory;
+    var elementFactory = this.test.libraryContext!.elementFactory;
     var libraryReferences = elementFactory.rootReference.children;
     return libraryReferences.map((e) => e.name).toSet();
   }
diff --git a/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart b/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart
index fd70b98..be38a3d 100644
--- a/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/sdk_version_gt_gt_gt_operator_test.dart
@@ -22,13 +22,13 @@
       '${ExperimentStatus.currentVersion.minor}';
 
   test_const_equals() async {
-    await verifyVersion('2.5.0', '''
+    await verifyVersion('2.15.0', '''
 const a = 42 >>> 3;
 ''');
   }
 
   test_const_lessThan() async {
-    await verifyVersion('2.2.0', '''
+    await verifyVersion('2.13.0', '''
 const a = 42 >>> 3;
 ''', expectedErrors: [
       error(HintCode.SDK_VERSION_GT_GT_GT_OPERATOR, 13, 3),
@@ -36,7 +36,7 @@
   }
 
   test_declaration_equals() async {
-    await verifyVersion('2.5.0', '''
+    await verifyVersion('2.15.0', '''
 class A {
   A operator >>>(A a) => this;
 }
@@ -44,7 +44,7 @@
   }
 
   test_declaration_lessThan() async {
-    await verifyVersion('2.2.0', '''
+    await verifyVersion('2.13.0', '''
 class A {
   A operator >>>(A a) => this;
 }
@@ -54,13 +54,13 @@
   }
 
   test_nonConst_equals() async {
-    await verifyVersion('2.5.0', '''
+    await verifyVersion('2.15.0', '''
 var a = 42 >>> 3;
 ''');
   }
 
   test_nonConst_lessThan() async {
-    await verifyVersion('2.2.0', '''
+    await verifyVersion('2.13.0', '''
 var a = 42 >>> 3;
 ''', expectedErrors: [
       error(HintCode.SDK_VERSION_GT_GT_GT_OPERATOR, 11, 3),
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index e41c85f..9c1892b 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -12209,24 +12209,24 @@
 
 ### sdk_version_gt_gt_gt_operator
 
-_The operator '>>>' wasn't supported until version 2.3.2, but this code is
+_The operator '>>>' wasn't supported until version 2.14.0, but this code is
 required to be able to run on earlier versions._
 
 #### Description
 
 The analyzer produces this diagnostic when the operator `>>>` is used in
-code that has an SDK constraint whose lower bound is less than 2.X.0. This
+code that has an SDK constraint whose lower bound is less than 2.14.0. This
 operator wasn't supported in earlier versions, so this code won't be able
 to run against earlier versions of the SDK.
 
 #### Examples
 
 Here's an example of a pubspec that defines an SDK constraint with a lower
-bound of less than 2.X.0:
+bound of less than 2.14.0:
 
 ```yaml
 environment:
- sdk: '>=2.0.0 <2.4.0'
+ sdk: '>=2.0.0 <2.15.0'
 ```
 
 In the package that has that pubspec, code like the following produces this
@@ -12243,7 +12243,7 @@
 
 ```yaml
 environment:
-  sdk: '>=2.3.2 <2.4.0'
+  sdk: '>=2.14.0 <2.15.0'
 ```
 
 If you need to support older versions of the SDK, then rewrite the code to
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 151bf0a..73cf9c2 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // Do not call exit() directly. Use VmInteropHandler.exit() instead.
+import 'dart:async';
 import 'dart:io' as io hide exit;
 import 'dart:isolate';
 
@@ -12,7 +13,6 @@
 import 'package:dart_style/src/cli/format_command.dart';
 import 'package:devtools_server/devtools_server.dart';
 import 'package:meta/meta.dart';
-import 'package:pedantic/pedantic.dart';
 import 'package:pub/pub.dart';
 import 'package:usage/usage.dart';
 
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index fb3e6d0..9fbdb4b 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -28,7 +28,6 @@
   nnbd_migration:
     path: ../nnbd_migration
   path: any
-  pedantic: any
   pub: any
   telemetry:
     path: ../telemetry
diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
index 953e36b..15f499b 100644
--- a/pkg/dds/CHANGELOG.md
+++ b/pkg/dds/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 2.1.3
+- Ensure cancelling multiple historical streams with the same name doesn't cause an
+  asynchronous `StateError` to be thrown.
+
 # 2.1.2
 - Silently handle exceptions that occur within RPC request handlers.
 
diff --git a/pkg/dds/lib/vm_service_extensions.dart b/pkg/dds/lib/vm_service_extensions.dart
index 09bda25..536fa57 100644
--- a/pkg/dds/lib/vm_service_extensions.dart
+++ b/pkg/dds/lib/vm_service_extensions.dart
@@ -91,7 +91,11 @@
       }
       unawaited(controller.sink.addStream(streamEvents.rest));
     }, onCancel: () {
-      streamEvents.cancel();
+      try {
+        streamEvents.cancel();
+      } on StateError {
+        // Underlying stream may have already been cancelled.
+      }
     });
 
     return controller.stream;
diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
index ae212ba..a477fca 100644
--- a/pkg/dds/pubspec.yaml
+++ b/pkg/dds/pubspec.yaml
@@ -3,7 +3,7 @@
   A library used to spawn the Dart Developer Service, used to communicate with
   a Dart VM Service instance.
 
-version: 2.1.2
+version: 2.1.3
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds
 
diff --git a/pkg/dds/test/regress_devtools_issue_3302_test.dart b/pkg/dds/test/regress_devtools_issue_3302_test.dart
new file mode 100644
index 0000000..8c97a12
--- /dev/null
+++ b/pkg/dds/test/regress_devtools_issue_3302_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:dds/dds.dart';
+import 'package:dds/vm_service_extensions.dart';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service_io.dart';
+import 'common/test_helper.dart';
+
+// Regression test for https://github.com/flutter/devtools/issues/3302.
+
+void main() {
+  late Process process;
+  late DartDevelopmentService dds;
+
+  setUp(() async {
+    process = await spawnDartProcess(
+      'smoke.dart',
+    );
+  });
+
+  tearDown(() async {
+    await dds.shutdown();
+    process.kill();
+  });
+
+  test(
+    'Ensure various historical streams can be cancelled without throwing StateError',
+    () async {
+      dds = await DartDevelopmentService.startDartDevelopmentService(
+        remoteVmServiceUri,
+      );
+      expect(dds.isRunning, true);
+      final service = await vmServiceConnectUri(dds.wsUri.toString());
+
+      // This creates two single-subscription streams which are backed by a
+      // broadcast stream.
+      final stream1 = service.onExtensionEventWithHistory;
+      final stream2 = service.onExtensionEventWithHistory;
+
+      // Subscribe to each stream so `cancel()` doesn't hang.
+      final sub1 = stream1.listen((_) => null);
+      final sub2 = stream2.listen((_) => null);
+
+      // Give some time for the streams to get setup.
+      await Future.delayed(const Duration(seconds: 1));
+
+      // The second call to `cancel()` shouldn't cause an exception to be thrown
+      // when we try to cancel the underlying broadcast stream again.
+      await sub1.cancel();
+      await sub2.cancel();
+    },
+    timeout: Timeout.none,
+  );
+}
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index cd72ba5..8aed5c6 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -50,6 +50,14 @@
   buffer_.Emit<int64_t>(value);
 }
 
+int32_t Assembler::BindImm26Branch(int64_t position, int64_t dest) {
+  ASSERT(CanEncodeImm26BranchOffset(dest));
+  const int32_t next = buffer_.Load<int32_t>(position);
+  const int32_t encoded = EncodeImm26BranchOffset(dest, next);
+  buffer_.Store<int32_t>(position, encoded);
+  return DecodeImm26BranchOffset(next);
+}
+
 int32_t Assembler::BindImm19Branch(int64_t position, int64_t dest) {
   if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) {
     // Far branches are enabled, and we can't encode the branch offset in
@@ -63,6 +71,7 @@
     const int32_t far_branch =
         buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
     const Condition c = DecodeImm19BranchCondition(guard_branch);
+    ASSERT(c != NV);
 
     // Grab the link to the next branch.
     const int32_t next = DecodeImm26BranchOffset(far_branch);
@@ -74,12 +83,6 @@
     // Encode the branch.
     const int32_t encoded_branch = EncodeImm26BranchOffset(offset, far_branch);
 
-    // If the guard branch is conditioned on NV, replace it with a nop.
-    if (c == NV) {
-      buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
-                             Instr::kNopInstruction);
-    }
-
     // Write the far branch into the buffer and link to the next branch.
     buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch);
     return next;
@@ -131,6 +134,7 @@
     const int32_t far_branch =
         buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
     const Condition c = DecodeImm14BranchCondition(guard_branch);
+    ASSERT(c != NV);
 
     // Grab the link to the next branch.
     const int32_t next = DecodeImm26BranchOffset(far_branch);
@@ -142,12 +146,6 @@
     // Encode the branch.
     const int32_t encoded_branch = EncodeImm26BranchOffset(offset, far_branch);
 
-    // If the guard branch is conditioned on NV, replace it with a nop.
-    if (c == NV) {
-      buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
-                             Instr::kNopInstruction);
-    }
-
     // Write the far branch into the buffer and link to the next branch.
     buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch);
     return next;
@@ -241,10 +239,15 @@
   while (label->IsLinked()) {
     const int64_t position = label->Position();
     const int64_t dest = bound_pc - position;
-    if (IsTestAndBranch(buffer_.Load<int32_t>(position))) {
+    const int32_t instr = buffer_.Load<int32_t>(position);
+    if (IsTestAndBranch(instr)) {
       label->position_ = BindImm14Branch(position, dest);
-    } else {
+    } else if (IsConditionalBranch(instr) || IsCompareAndBranch(instr)) {
       label->position_ = BindImm19Branch(position, dest);
+    } else if (IsUnconditionalBranch(instr)) {
+      label->position_ = BindImm26Branch(position, dest);
+    } else {
+      UNREACHABLE();
     }
   }
   label->BindTo(bound_pc, lr_state());
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 4484fb5..d2432b5 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1221,7 +1221,11 @@
 
   // Conditional branch.
   void b(Label* label, Condition cond = AL) {
-    EmitConditionalBranch(BCOND, cond, label);
+    if (cond == AL) {
+      EmitUnconditionalBranch(B, label);
+    } else {
+      EmitConditionalBranch(BCOND, cond, label);
+    }
   }
 
   void b(int32_t offset) { EmitUnconditionalBranchOp(B, offset); }
@@ -2369,6 +2373,7 @@
     Emit(encoding);
   }
 
+  int32_t BindImm26Branch(int64_t position, int64_t dest);
   int32_t BindImm19Branch(int64_t position, int64_t dest);
   int32_t BindImm14Branch(int64_t position, int64_t dest);
 
@@ -2406,6 +2411,11 @@
     return static_cast<int64_t>(off);
   }
 
+  bool IsUnconditionalBranch(int32_t instr) {
+    return (instr & UnconditionalBranchMask) ==
+           (UnconditionalBranchFixed & UnconditionalBranchMask);
+  }
+
   bool IsConditionalBranch(int32_t instr) {
     return (instr & ConditionalBranchMask) ==
            (ConditionalBranchFixed & ConditionalBranchMask);
@@ -2486,6 +2496,7 @@
   void EmitConditionalBranchOp(ConditionalBranchOp op,
                                Condition cond,
                                int64_t imm) {
+    ASSERT(cond != AL);
     const int32_t off = EncodeImm19BranchOffset(imm, 0);
     const int32_t encoding =
         op | (static_cast<int32_t>(cond) << kCondShift) | off;
@@ -2505,21 +2516,16 @@
   void EmitConditionalBranch(ConditionalBranchOp op,
                              Condition cond,
                              Label* label) {
+    ASSERT(cond != AL);
     if (label->IsBound()) {
       const int64_t dest = label->Position() - buffer_.Size();
       if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) {
-        if (cond == AL) {
-          // If the condition is AL, we must always branch to dest. There is
-          // no need for a guard branch.
-          b(dest);
-        } else {
-          EmitConditionalBranchOp(op, InvertCondition(cond),
-                                  2 * Instr::kInstrSize);
-          // Make a new dest that takes the new position into account after the
-          // inverted test.
-          const int64_t dest = label->Position() - buffer_.Size();
-          b(dest);
-        }
+        EmitConditionalBranchOp(op, InvertCondition(cond),
+                                2 * Instr::kInstrSize);
+        // Make a new dest that takes the new position into account after the
+        // inverted test.
+        const int64_t dest = label->Position() - buffer_.Size();
+        b(dest);
       } else {
         EmitConditionalBranchOp(op, cond, dest);
       }
@@ -2612,6 +2618,18 @@
     Emit(encoding);
   }
 
+  void EmitUnconditionalBranch(UnconditionalBranchOp op, Label* label) {
+    if (label->IsBound()) {
+      const int64_t dest = label->Position() - buffer_.Size();
+      EmitUnconditionalBranchOp(op, dest);
+      label->UpdateLRState(lr_state());
+    } else {
+      const int64_t position = buffer_.Size();
+      EmitUnconditionalBranchOp(op, label->position_);
+      label->LinkTo(position, lr_state());
+    }
+  }
+
   void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) {
     ASSERT((rn != CSP) && (rn != R31));
     const int32_t encoding = op | Arm64Encode::Rn(rn);
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index e23657c..28ac726 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -549,9 +549,7 @@
   COMPILE_ASSERT((GE ^ LT) == 1);
   COMPILE_ASSERT((GT ^ LE) == 1);
   COMPILE_ASSERT((AL ^ NV) == 1);
-  // Although the NV condition is not valid for branches, it is used internally
-  // in the assembler in the implementation of far branches, so we have to
-  // allow AL and NV here. See EmitConditionalBranch.
+  ASSERT(c != AL);
   ASSERT(c != kInvalidCondition);
   return static_cast<Condition>(c ^ 1);
 }
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index df6013c..2d0ca6e 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -80,6 +80,12 @@
   static String get operatingSystem => _operatingSystem;
 
   /// A string representing the version of the operating system or platform.
+  ///
+  /// The format of this string will vary by operating system, platform and
+  /// version and is not suitable for parsing. For example:
+  ///   "Linux 5.11.0-1018-gcp #20~20.04.2-Ubuntu SMP Fri Sep 3 01:01:37 UTC 2021"
+  ///   "Version 14.5 (Build 18E182)"
+  ///   '"Windows 10 Pro" 10.0 (Build 19043)'
   static String get operatingSystemVersion => _operatingSystemVersion;
 
   /// The local hostname for the system.
diff --git a/tools/VERSION b/tools/VERSION
index 9ad0a02..9936ef2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 153
+PRERELEASE 154
 PRERELEASE_PATCH 0
\ No newline at end of file