Version 3.11.0-45.0.dev

Merge 5b1be80bf9c741f1ebb6843270d469052c1c623f into dev
diff --git a/DEPS b/DEPS
index 73924eb..490d4f8 100644
--- a/DEPS
+++ b/DEPS
@@ -75,7 +75,7 @@
   "jsc_tag": "version:301576",
 
   # https://chrome-infra-packages.appspot.com/p/fuchsia/third_party/clang
-  "clang_version": "git_revision:9d7449a82b83ee589b8af8d6f86525727788b3b9",
+  "clang_version": "git_revision:8b93f27cf7e6e53636db870873b53269efa3cca4",
 
   # https://chrome-infra-packages.appspot.com/p/gn/gn
   "gn_version": "git_revision:07d3c6f4dc290fae5ca6152ebcb37d6815c411ab",
@@ -147,10 +147,10 @@
   "sync_http_rev": "6666fff944221891182e1f80bf56569338164d72",
   "tar_rev": "13479f7c2a18f499e840ad470cfcca8c579f6909",
   "test_rev": "8083c8f24ffbca58cc0385add03c296b70636e7a",
-  "tools_rev": "d0941a357a297610f012114d4da06fcccebe6c5c",
+  "tools_rev": "ce126700df1901b5782e38320b389a674912d0d0",
   "vector_math_rev": "a7b7e9ccb931348dbfa669e0f8fea1bf97705b16",
   "web_rev": "5a7d0be70a258252b95bac6b900f26d6dae4d433",
-  "webdev_rev": "82b385574a65e6025f970ce204365851dbbc1ac1",
+  "webdev_rev": "b9c39c00853dfad0e235bec3b265f86a0f4f328a",
   "webdriver_rev": "09104f459ed834d48b132f6b7734923b1fbcf2e9",
   "webkit_inspection_protocol_rev": "0f7685804d77ec02c6564d7ac1a6c8a2341c5bdf",
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
index 0ce6417..a7b1149 100644
--- a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
@@ -476,6 +476,11 @@
   }
 
   @override
+  bool? visitNullAwareElement(NullAwareElement node) {
+    return _nodeExits(node.value);
+  }
+
+  @override
   bool visitParenthesizedExpression(ParenthesizedExpression node) =>
       node.expression.accept(this)!;
 
diff --git a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
index ded19fd..f3257bd 100644
--- a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
+++ b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
@@ -108,6 +108,10 @@
     _assertFalse('[if (c) throw 42 else 0]');
   }
 
+  test_nullAwareElement() async {
+    _assertFalse('[?0]');
+  }
+
   void _assertFalse(String expressionCode) {
     _assertHasReturn(expressionCode, false);
   }
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index 7c467b3..a1c53b2 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -63,10 +63,10 @@
 const _noResult = null;
 
 /// Pattern for extracting useful error messages from an evaluation exception.
-final _evalErrorMessagePattern = RegExp('Error: (.*)');
+final _evalErrorMessagePattern = RegExp('Error: (.+)');
 
 /// Pattern for extracting useful error messages from an unhandled exception.
-final _exceptionMessagePattern = RegExp('Unhandled exception:\n(.*)');
+final _exceptionMessagePattern = RegExp('Unhandled exception:\n(.+)');
 
 /// Pattern for a trailing semicolon.
 final _trailingSemicolonPattern = RegExp(r';$');
@@ -1124,26 +1124,24 @@
         result = await vmEvaluate(thread, library.id!, expression);
       }
     } catch (e) {
-      final rawMessage = '$e';
-
-      // Error messages can be quite verbose and don't fit well into a
-      // single-line watch window. For example:
+      // Expression compilation errors may result in exceptions here (failed
+      // RCP requests) rather than a returned vm.ErrorRef:
       //
       //    evaluateInFrame: (113) Expression compilation error
       //    org-dartlang-debug:synthetic_debug_expression:1:5: Error: A value of type 'String' can't be assigned to a variable of type 'num'.
       //    1 + "a"
       //        ^
-      //
-      // So in the case of a Watch context, try to extract the useful message.
-      if (args.context == 'watch') {
-        throw DebugAdapterException(extractEvaluationErrorMessage(rawMessage));
-      }
-
-      throw DebugAdapterException(rawMessage);
+      _throwEvalError(args, '$e');
     }
 
     if (result is vm.ErrorRef) {
-      throw DebugAdapterException(result.message ?? '<error ref>');
+      // Some kinds of errors will return ErrorRefs:
+      //
+      // Unhandled exception:
+      // NoSuchMethodError: Class 'DateTime' has no instance getter 'ye'.
+      // Receiver: Instance of 'DateTime'
+      // Tried calling: ye
+      _throwEvalError(args, result.message ?? '<error ref>');
     } else if (result is vm.Sentinel) {
       throw DebugAdapterException(result.valueAsString ?? '<collected>');
     } else if (result is vm.InstanceRef && thread != null) {
@@ -1183,6 +1181,19 @@
     }
   }
 
+  /// Throws a [DebugAdapterException] for an expression evaluation error.
+  ///
+  /// For some contexts, parts of the error message may be extracted resulting
+  /// in a shorter message (for example to provide less noise in a Watch
+  /// window).
+  Never _throwEvalError(EvaluateArguments args, String message) {
+    if (args.context == 'watch') {
+      message = extractEvaluationErrorMessage(message);
+    }
+
+    throw DebugAdapterException(message);
+  }
+
   /// Tries to extract the useful part from an evaluation exception message.
   ///
   /// If no message could be extracted, returns the whole original error.
diff --git a/pkg/dds/test/dap/integration/debug_eval_test.dart b/pkg/dds/test/dap/integration/debug_eval_test.dart
index 4a050f8..5fd6726 100644
--- a/pkg/dds/test/dap/integration/debug_eval_test.dart
+++ b/pkg/dds/test/dap/integration/debug_eval_test.dart
@@ -196,7 +196,8 @@
       );
     });
 
-    test('returns short errors for evaluation in "watch" context', () async {
+    test('returns short errors for evaluation in "watch" context (rpc error)',
+        () async {
       final client = dap.client;
       final testFile = dap.createTestFile(simpleBreakpointProgram);
       final breakpointLine = lineWith(testFile, breakpointMarker);
@@ -205,6 +206,8 @@
       final topFrameId = await client.getTopFrameId(stop.threadId!);
       expectResponseError(
         client.evaluate(
+          // This expression fails with an RPC error (expression compilation)
+          // so will be handled as a failed request in the DAP handler.
           '1 + "a"',
           frameId: topFrameId,
           context: 'watch',
@@ -216,6 +219,26 @@
       );
     });
 
+    test('returns short errors for evaluation in "watch" context (ErrorRef)',
+        () async {
+      final client = dap.client;
+      final testFile = dap.createTestFile(simpleBreakpointProgram);
+      final breakpointLine = lineWith(testFile, breakpointMarker);
+
+      final stop = await client.hitBreakpoint(testFile, breakpointLine);
+      final topFrameId = await client.getTopFrameId(stop.threadId!);
+      expectResponseError(
+        client.evaluate(
+          // This expression compiles but returns an ErrorRef which must be
+          // handled specifically in the DAP handler.
+          'DateTime.now().ye',
+          frameId: topFrameId,
+          context: 'watch',
+        ),
+        equals("Class 'DateTime' has no instance getter 'ye'."),
+      );
+    });
+
     test('returns truncated strings by default', () async {
       final client = dap.client;
       final testFile = dap.createTestFile(simpleBreakpointProgram);
diff --git a/runtime/tools/dartfuzz/flag_fuzzer.dart b/runtime/tools/dartfuzz/flag_fuzzer.dart
index 4f028a4..0b638ad 100644
--- a/runtime/tools/dartfuzz/flag_fuzzer.dart
+++ b/runtime/tools/dartfuzz/flag_fuzzer.dart
@@ -159,10 +159,14 @@
   }
 }
 
-test(List<String> Function(String) createDartCommand, int taskIndex) async {
+test(
+  List<String> Function(String) createDartCommand,
+  int taskIndex,
+  String extension,
+) async {
   taskStart();
 
-  var dartCommand = createDartCommand("out/dartfuzz/$taskIndex.js");
+  var dartCommand = createDartCommand("out/dartfuzz/$taskIndex.$extension");
   var dartScript = dartCommand[0];
   var dartArguments = dartCommand.getRange(1, dartCommand.length).toList();
 
@@ -177,7 +181,11 @@
         dartScript,
         ...dartArguments,
       ],
-      ["diff", "out/dartfuzz/expected.js", "out/dartfuzz/$taskIndex.js"],
+      [
+        "diff",
+        "out/dartfuzz/expected.$extension",
+        "out/dartfuzz/$taskIndex.$extension",
+      ],
     ];
   } else {
     // AOT
@@ -203,7 +211,11 @@
         "out/dartfuzz/$taskIndex.elf",
         ...dartArguments,
       ],
-      ["diff", "out/dartfuzz/expected.js", "out/dartfuzz/$taskIndex.js"],
+      [
+        "diff",
+        "out/dartfuzz/expected.$extension",
+        "out/dartfuzz/$taskIndex.$extension",
+      ],
     ];
   }
 
@@ -254,19 +266,26 @@
   taskEnd();
 }
 
-shard(List<String> Function(String) createDartCommand, int shardIndex) async {
+shard(
+  List<String> Function(String) createDartCommand,
+  int shardIndex,
+  String extension,
+) async {
   while (!remainingTimeout.isNegative) {
-    await test(createDartCommand, shardIndex);
+    await test(createDartCommand, shardIndex, extension);
   }
 }
 
-flagFuzz(List<String> Function(String) createDartCommand) async {
+flagFuzz(
+  List<String> Function(String) createDartCommand,
+  String extension,
+) async {
   stopwatch.start();
 
   await Directory("out/dartfuzz").create();
 
   var executable = "out/ReleaseX64/dart";
-  var arguments = createDartCommand("out/dartfuzz/expected.js");
+  var arguments = createDartCommand("out/dartfuzz/expected.$extension");
   var processResult = await Process.run(executable, arguments);
   if (processResult.exitCode != 0) {
     print("=== FAILURE ===");
@@ -280,6 +299,6 @@
   }
 
   for (var i = 0; i < Platform.numberOfProcessors; i++) {
-    shard(createDartCommand, i);
+    shard(createDartCommand, i, extension);
   }
 }
diff --git a/runtime/tools/dartfuzz/flag_fuzzer_dart2js.dart b/runtime/tools/dartfuzz/flag_fuzzer_dart2js.dart
index 9a4b462..16cb486 100644
--- a/runtime/tools/dartfuzz/flag_fuzzer_dart2js.dart
+++ b/runtime/tools/dartfuzz/flag_fuzzer_dart2js.dart
@@ -16,4 +16,5 @@
     "--no-source-maps", // Otherwise output includes path
     "pkg/compiler/lib/src/util/memory_compiler.dart",
   ],
+  "js",
 );
diff --git a/runtime/tools/dartfuzz/flag_fuzzer_dart2wasm.dart b/runtime/tools/dartfuzz/flag_fuzzer_dart2wasm.dart
index e088c6e..56a39c6 100644
--- a/runtime/tools/dartfuzz/flag_fuzzer_dart2wasm.dart
+++ b/runtime/tools/dartfuzz/flag_fuzzer_dart2wasm.dart
@@ -15,4 +15,5 @@
     "pkg/compiler/lib/src/util/memory_compiler.dart",
     output,
   ],
+  "wasm",
 );
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 84f9888..abd267a 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -1929,11 +1929,54 @@
 }
 
 void Assembler::PushRegisters(const RegisterSet& registers) {
-  UNIMPLEMENTED();
+  const intptr_t xmm_regs_count = registers.FpuRegisterCount();
+  if (xmm_regs_count > 0) {
+    subl(ESP, compiler::Immediate(xmm_regs_count * kFpuRegisterSize));
+    // Store XMM registers with the lowest register number at the lowest
+    // address.
+    intptr_t offset = 0;
+    for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) {
+      XmmRegister xmm_reg = static_cast<XmmRegister>(i);
+      if (registers.ContainsFpuRegister(xmm_reg)) {
+        movups(Address(ESP, offset), xmm_reg);
+        offset += kFpuRegisterSize;
+      }
+    }
+    ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
+  }
+
+  // The order in which the registers are pushed must match the order
+  // in which the registers are encoded in the safe point's stack map.
+  for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) {
+    Register reg = static_cast<Register>(i);
+    if (registers.ContainsRegister(reg)) {
+      pushl(reg);
+    }
+  }
 }
 
 void Assembler::PopRegisters(const RegisterSet& registers) {
-  UNIMPLEMENTED();
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+    Register reg = static_cast<Register>(i);
+    if (registers.ContainsRegister(reg)) {
+      popl(reg);
+    }
+  }
+
+  const intptr_t xmm_regs_count = registers.FpuRegisterCount();
+  if (xmm_regs_count > 0) {
+    // XMM registers have the lowest register number at the lowest address.
+    intptr_t offset = 0;
+    for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) {
+      XmmRegister xmm_reg = static_cast<XmmRegister>(i);
+      if (registers.ContainsFpuRegister(xmm_reg)) {
+        movups(xmm_reg, Address(ESP, offset));
+        offset += kFpuRegisterSize;
+      }
+    }
+    ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
+    addl(ESP, compiler::Immediate(offset));
+  }
 }
 
 void Assembler::PushRegistersInOrder(std::initializer_list<Register> regs) {
@@ -2610,9 +2653,8 @@
        compiler::Immediate(0));
 }
 
-static constexpr intptr_t kNumberOfVolatileCpuRegisters = 3;
-static const Register volatile_cpu_registers[kNumberOfVolatileCpuRegisters] = {
-    EAX, ECX, EDX};
+static const RegisterSet kRuntimeCallSavedRegisters(kDartVolatileCpuRegs,
+                                                    kDartVolatileFpuRegs);
 
 void Assembler::CallRuntime(const RuntimeEntry& entry,
                             intptr_t argument_count,
@@ -2635,21 +2677,7 @@
   __ EnterFrame(0);
 
   if (preserve_registers_) {
-    // Preserve volatile CPU registers.
-    for (intptr_t i = 0; i < kNumberOfVolatileCpuRegisters; i++) {
-      __ pushl(volatile_cpu_registers[i]);
-    }
-
-    // Preserve all XMM registers.
-    __ subl(ESP, Immediate(kNumberOfXmmRegisters * kFpuRegisterSize));
-    // Store XMM registers with the lowest register number at the lowest
-    // address.
-    intptr_t offset = 0;
-    for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
-      XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
-      __ movups(Address(ESP, offset), xmm_reg);
-      offset += kFpuRegisterSize;
-    }
+    __ PushRegisters(kRuntimeCallSavedRegisters);
   } else {
     // These registers must always be preserved.
     COMPILE_ASSERT(IsCalleeSavedRegister(THR));
@@ -2674,25 +2702,9 @@
     // ESP might have been modified to reserve space for arguments
     // and ensure proper alignment of the stack frame.
     // We need to restore it before restoring registers.
-    const intptr_t kPushedRegistersSize =
-        kNumberOfVolatileCpuRegisters * target::kWordSize +
-        kNumberOfXmmRegisters * kFpuRegisterSize;
-    __ leal(ESP, Address(EBP, -kPushedRegistersSize));
+    __ leal(ESP, Address(EBP, -kRuntimeCallSavedRegisters.SpillSize()));
 
-    // Restore all XMM registers.
-    // XMM registers have the lowest register number at the lowest address.
-    intptr_t offset = 0;
-    for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
-      XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
-      __ movups(xmm_reg, Address(ESP, offset));
-      offset += kFpuRegisterSize;
-    }
-    __ addl(ESP, Immediate(offset));
-
-    // Restore volatile CPU registers.
-    for (intptr_t i = kNumberOfVolatileCpuRegisters - 1; i >= 0; i--) {
-      __ popl(volatile_cpu_registers[i]);
-    }
+    __ PopRegisters(kRuntimeCallSavedRegisters);
   }
 
   __ leave();
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 0e05e3c..41f1b78 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -699,56 +699,12 @@
   locs->CheckWritableInputs();
   ClobberDeadTempRegisters(locs);
 #endif
-
   // TODO(vegorov): consider saving only caller save (volatile) registers.
-  const intptr_t xmm_regs_count = locs->live_registers()->FpuRegisterCount();
-  if (xmm_regs_count > 0) {
-    __ subl(ESP, compiler::Immediate(xmm_regs_count * kFpuRegisterSize));
-    // Store XMM registers with the lowest register number at the lowest
-    // address.
-    intptr_t offset = 0;
-    for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) {
-      XmmRegister xmm_reg = static_cast<XmmRegister>(i);
-      if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) {
-        __ movups(compiler::Address(ESP, offset), xmm_reg);
-        offset += kFpuRegisterSize;
-      }
-    }
-    ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
-  }
-
-  // The order in which the registers are pushed must match the order
-  // in which the registers are encoded in the safe point's stack map.
-  for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) {
-    Register reg = static_cast<Register>(i);
-    if (locs->live_registers()->ContainsRegister(reg)) {
-      __ pushl(reg);
-    }
-  }
+  __ PushRegisters(*locs->live_registers());
 }
 
 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) {
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    Register reg = static_cast<Register>(i);
-    if (locs->live_registers()->ContainsRegister(reg)) {
-      __ popl(reg);
-    }
-  }
-
-  const intptr_t xmm_regs_count = locs->live_registers()->FpuRegisterCount();
-  if (xmm_regs_count > 0) {
-    // XMM registers have the lowest register number at the lowest address.
-    intptr_t offset = 0;
-    for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) {
-      XmmRegister xmm_reg = static_cast<XmmRegister>(i);
-      if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) {
-        __ movups(xmm_reg, compiler::Address(ESP, offset));
-        offset += kFpuRegisterSize;
-      }
-    }
-    ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
-    __ addl(ESP, compiler::Immediate(offset));
-  }
+  __ PopRegisters(*locs->live_registers());
 }
 
 #if defined(DEBUG)
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 909b6ff..78cda92 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -1246,7 +1246,7 @@
 ConstantInstr* GraphEntryInstr::constant_null() {
   ASSERT(initial_definitions()->length() > 0);
   for (intptr_t i = 0; i < initial_definitions()->length(); ++i) {
-    ConstantInstr* defn = (*initial_definitions())[i] -> AsConstant();
+    ConstantInstr* defn = (*initial_definitions())[i]->AsConstant();
     if (defn != nullptr && defn->value().IsNull()) return defn;
   }
   UNREACHABLE();
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 2001717..175c61e 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -1520,7 +1520,7 @@
     for (intptr_t i = 0; i < phis()->length(); ++i) {
       if ((*phis())[i] == nullptr) continue;
       f->AddString("\n      ");
-      (*phis())[i] -> PrintTo(f);
+      (*phis())[i]->PrintTo(f);
     }
     f->AddString("\n}");
   }
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index 6a5f993..c8c3172 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -393,11 +393,12 @@
 
 const RegList kAbiPreservedCpuRegs = (1 << EDI) | (1 << ESI) | (1 << EBX);
 
+const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList;
+
 // Registers available to Dart that are not preserved by runtime calls.
 const RegList kDartVolatileCpuRegs =
     kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
-
-const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList;
+const RegList kDartVolatileFpuRegs = kAbiVolatileFpuRegs & ~(1 << FpuTMP);
 
 #undef R
 
diff --git a/runtime/vm/regexp/regexp_ast.cc b/runtime/vm/regexp/regexp_ast.cc
index 884fed9..3bfd878 100644
--- a/runtime/vm/regexp/regexp_ast.cc
+++ b/runtime/vm/regexp/regexp_ast.cc
@@ -145,7 +145,7 @@
   OS::PrintErr("(|");
   for (intptr_t i = 0; i < that->alternatives()->length(); i++) {
     OS::PrintErr(" ");
-    (*that->alternatives())[i] -> Accept(this, data);
+    (*that->alternatives())[i]->Accept(this, data);
   }
   OS::PrintErr(")");
   return nullptr;
@@ -155,7 +155,7 @@
   OS::PrintErr("(:");
   for (intptr_t i = 0; i < that->nodes()->length(); i++) {
     OS::PrintErr(" ");
-    (*that->nodes())[i] -> Accept(this, data);
+    (*that->nodes())[i]->Accept(this, data);
   }
   OS::PrintErr(")");
   return nullptr;
diff --git a/tools/VERSION b/tools/VERSION
index 56567be..c7e24e7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 11
 PATCH 0
-PRERELEASE 44
+PRERELEASE 45
 PRERELEASE_PATCH 0