Version 2.18.0-93.0.dev

Merge commit '4d77e3e64554f260a60f6cbca158a50f6a63b2a2' into 'dev'
diff --git a/pkg/vm_service/test/regress_88104_test.dart b/pkg/vm_service/test/regress_88104_test.dart
new file mode 100644
index 0000000..b864dfd
--- /dev/null
+++ b/pkg/vm_service/test/regress_88104_test.dart
@@ -0,0 +1,48 @@
+// 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.
+
+// Regression test for https://github.com/flutter/flutter/issues/88104.
+//
+// Ensures that the `TypeArguments` register is correctly preserved when
+// regenerating the allocation stub for generic classes after enabling
+// allocation tracing.
+import 'dart:async';
+import 'dart:developer';
+
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+class Foo<T> {}
+
+testMain() async {
+  debugger();
+  for (int i = 0; i < 10; ++i) {
+    Foo<int>();
+    await Future.delayed(const Duration(milliseconds: 10));
+  }
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+    final rootLib = await service.getObject(isolateId, rootLibId) as Library;
+    final fooCls = rootLib.classes!.first;
+    await service.setTraceClassAllocation(isolateId, fooCls.id!, true);
+  },
+  resumeIsolate,
+  hasStoppedAtExit,
+];
+
+main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regress_88104_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_exit: true,
+    );
diff --git a/runtime/tests/vm/dart/regress_48948_test.dart b/runtime/tests/vm/dart/regress_48948_test.dart
deleted file mode 100644
index 2a334b3..0000000
--- a/runtime/tests/vm/dart/regress_48948_test.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-
-// Regression test for https://github.com/dart-lang/sdk/issues/48948.
-
-import 'package:expect/expect.dart';
-
-class Foo {
-  const Foo(this.x, this.y);
-
-  final int x;
-  final int y;
-
-  static int hashCodeCounter = 0;
-
-  @override
-  int get hashCode {
-    hashCodeCounter++;
-    return x.hashCode ^ y.hashCode;
-  }
-}
-
-void main() {
-  final Map<Foo, int> someMap = {};
-  final Set<Foo> someSet = {};
-  Expect.equals(0, Foo.hashCodeCounter);
-
-  someMap[Foo(1, 100)] = 2;
-  Expect.equals(1, Foo.hashCodeCounter);
-
-  someSet.add(Foo(1, 100));
-  Expect.equals(2, Foo.hashCodeCounter);
-}
diff --git a/runtime/tests/vm/dart_2/regress_48948_test.dart b/runtime/tests/vm/dart_2/regress_48948_test.dart
deleted file mode 100644
index 0e71942..0000000
--- a/runtime/tests/vm/dart_2/regress_48948_test.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-// Regression test for https://github.com/dart-lang/sdk/issues/48948.
-
-// @dart = 2.9
-
-import 'package:expect/expect.dart';
-
-class Foo {
-  const Foo(this.x, this.y);
-
-  final int x;
-  final int y;
-
-  static int hashCodeCounter = 0;
-
-  @override
-  int get hashCode {
-    hashCodeCounter++;
-    return x.hashCode ^ y.hashCode;
-  }
-}
-
-void main() {
-  final Map<Foo, int> someMap = {};
-  final Set<Foo> someSet = {};
-  Expect.equals(0, Foo.hashCodeCounter);
-
-  someMap[Foo(1, 100)] = 2;
-  Expect.equals(1, Foo.hashCodeCounter);
-
-  someSet.add(Foo(1, 100));
-  Expect.equals(2, Foo.hashCodeCounter);
-}
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 5af92dc..fc6b0ea 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -737,6 +737,33 @@
   __ Branch(FieldAddress(R0, target::Code::entry_point_offset()));
 }
 
+// Called from object allocate instruction when the allocation stub for a
+// generic class has been disabled.
+void StubCodeCompiler::GenerateFixParameterizedAllocationStubTargetStub(
+    Assembler* assembler) {
+  // Load code pointer to this stub from the thread:
+  // The one that is passed in, is not correct - it points to the code object
+  // that needs to be replaced.
+  __ ldr(CODE_REG,
+         Address(THR, target::Thread::fix_allocation_stub_code_offset()));
+  __ EnterStubFrame();
+  // Preserve type arguments register.
+  __ Push(AllocateObjectABI::kTypeArgumentsReg);
+  // Setup space on stack for return value.
+  __ LoadImmediate(R0, 0);
+  __ Push(R0);
+  __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
+  // Get Code object result.
+  __ Pop(R0);
+  // Restore type arguments register.
+  __ Push(AllocateObjectABI::kTypeArgumentsReg);
+  // Remove the stub frame.
+  __ LeaveStubFrame();
+  // Jump to the dart function.
+  __ mov(CODE_REG, Operand(R0));
+  __ Branch(FieldAddress(R0, target::Code::entry_point_offset()));
+}
+
 // Input parameters:
 //   R2: smi-tagged argument count, may be zero.
 //   FP[target::frame_layout.param_end_from_fp + 1]: last argument.
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index ee14dd9..ab3c748 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -972,6 +972,32 @@
   __ br(R0);
 }
 
+// Called from object allocate instruction when the allocation stub for a
+// generic class has been disabled.
+void StubCodeCompiler::GenerateFixParameterizedAllocationStubTargetStub(
+    Assembler* assembler) {
+  // Load code pointer to this stub from the thread:
+  // The one that is passed in, is not correct - it points to the code object
+  // that needs to be replaced.
+  __ ldr(CODE_REG,
+         Address(THR, target::Thread::fix_allocation_stub_code_offset()));
+  __ EnterStubFrame();
+  // Preserve type arguments register.
+  __ Push(AllocateObjectABI::kTypeArgumentsReg);
+  // Setup space on stack for return value.
+  __ Push(ZR);
+  __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
+  // Get Code object result.
+  __ Pop(CODE_REG);
+  // Restore type arguments register.
+  __ Pop(AllocateObjectABI::kTypeArgumentsReg);
+  // Remove the stub frame.
+  __ LeaveStubFrame();
+  // Jump to the dart function.
+  __ LoadFieldFromOffset(R0, CODE_REG, target::Code::entry_point_offset());
+  __ br(R0);
+}
+
 // Input parameters:
 //   R2: smi-tagged argument count, may be zero.
 //   FP[target::frame_layout.param_end_from_fp + 1]: last argument.
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index ad1f072..3f0639f 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -558,6 +558,24 @@
   __ int3();
 }
 
+// Called from object allocate instruction when the allocation stub for a
+// generic class has been disabled.
+void StubCodeCompiler::GenerateFixParameterizedAllocationStubTargetStub(
+    Assembler* assembler) {
+  __ EnterStubFrame();
+  // Preserve type arguments register.
+  __ pushl(AllocateObjectABI::kTypeArgumentsReg);
+  __ pushl(Immediate(0));  // Setup space on stack for return value.
+  __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
+  __ popl(EAX);  // Get Code object.
+  // Restore type arguments register.
+  __ popl(AllocateObjectABI::kTypeArgumentsReg);
+  __ movl(EAX, FieldAddress(EAX, target::Code::entry_point_offset()));
+  __ LeaveFrame();
+  __ jmp(EAX);
+  __ int3();
+}
+
 // Input parameters:
 //   EDX: smi-tagged argument count, may be zero.
 //   EBP[target::frame_layout.param_end_from_fp + 1]: last argument.
diff --git a/runtime/vm/compiler/stub_code_compiler_riscv.cc b/runtime/vm/compiler/stub_code_compiler_riscv.cc
index 0faaa88..b9fc91d 100644
--- a/runtime/vm/compiler/stub_code_compiler_riscv.cc
+++ b/runtime/vm/compiler/stub_code_compiler_riscv.cc
@@ -791,6 +791,32 @@
   __ jr(TMP);
 }
 
+// Called from object allocate instruction when the allocation stub for a
+// generic class has been disabled.
+void StubCodeCompiler::GenerateFixParameterizedAllocationStubTargetStub(
+    Assembler* assembler) {
+  // Load code pointer to this stub from the thread:
+  // The one that is passed in, is not correct - it points to the code object
+  // that needs to be replaced.
+  __ lx(CODE_REG,
+        Address(THR, target::Thread::fix_allocation_stub_code_offset()));
+  __ EnterStubFrame();
+  // Preserve type arguments register.
+  __ PushRegister(AllocateObjectABI::kTypeArgumentsReg);
+  // Setup space on stack for return value.
+  __ PushRegister(ZR);
+  __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
+  // Get Code object result.
+  __ PopRegister(CODE_REG);
+  // Restore type arguments register.
+  __ PopRegister(AllocateObjectABI::kTypeArgumentsReg);
+  // Remove the stub frame.
+  __ LeaveStubFrame();
+  // Jump to the dart function.
+  __ LoadFieldFromOffset(TMP, CODE_REG, target::Code::entry_point_offset());
+  __ jr(TMP);
+}
+
 // Input parameters:
 //   T2: smi-tagged argument count, may be zero.
 //   FP[target::frame_layout.param_end_from_fp + 1]: last argument.
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 2b8bb2a..92e562e 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -877,6 +877,28 @@
   __ int3();
 }
 
+// Called from object allocate instruction when the allocation stub for a
+// generic class has been disabled.
+void StubCodeCompiler::GenerateFixParameterizedAllocationStubTargetStub(
+    Assembler* assembler) {
+  // Load code pointer to this stub from the thread:
+  // The one that is passed in, is not correct - it points to the code object
+  // that needs to be replaced.
+  __ movq(CODE_REG,
+          Address(THR, target::Thread::fix_allocation_stub_code_offset()));
+  __ EnterStubFrame();
+  // Setup space on stack for return value.
+  __ pushq(AllocateObjectABI::kTypeArgumentsReg);
+  __ pushq(Immediate(0));
+  __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0);
+  __ popq(CODE_REG);  // Get Code object.
+  __ popq(AllocateObjectABI::kTypeArgumentsReg);
+  __ movq(RAX, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
+  __ LeaveStubFrame();
+  __ jmp(RAX);
+  __ int3();
+}
+
 // Input parameters:
 //   R10: smi-tagged argument count, may be zero.
 //   RBP[target::frame_layout.param_end_from_fp + 1]: last argument.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c454796..86e583b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5398,7 +5398,7 @@
   }
   ASSERT(!existing_stub.IsDisabled());
   // Change the stub so that the next caller will regenerate the stub.
-  existing_stub.DisableStubCode();
+  existing_stub.DisableStubCode(NumTypeParameters() > 0);
   // Disassociate the existing stub from class.
   untag()->set_allocation_stub(Code::null());
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
@@ -17641,11 +17641,13 @@
                         new_code.UncheckedEntryPointOffset());
 }
 
-void Code::DisableStubCode() const {
+void Code::DisableStubCode(bool is_cls_parameterized) const {
   GcSafepointOperationScope safepoint(Thread::Current());
   ASSERT(IsAllocationStubCode());
   ASSERT(instructions() == active_instructions());
-  const Code& new_code = StubCode::FixAllocationStubTarget();
+  const Code& new_code = is_cls_parameterized
+                             ? StubCode::FixParameterizedAllocationStubTarget()
+                             : StubCode::FixAllocationStubTarget();
   SetActiveInstructions(Instructions::Handle(new_code.instructions()),
                         new_code.UncheckedEntryPointOffset());
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 19f2fd3..6f226c3 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -6857,7 +6857,7 @@
 
   void DisableDartCode() const;
 
-  void DisableStubCode() const;
+  void DisableStubCode(bool is_cls_parameterized) const;
 
   void Enable() const {
     if (!IsDisabled()) return;
diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h
index f9110be..39e1f49 100644
--- a/runtime/vm/stub_code_list.h
+++ b/runtime/vm/stub_code_list.h
@@ -75,6 +75,7 @@
   V(ICCallThroughCode)                                                         \
   V(MegamorphicCall)                                                           \
   V(FixAllocationStubTarget)                                                   \
+  V(FixParameterizedAllocationStubTarget)                                      \
   V(Deoptimize)                                                                \
   V(DeoptimizeLazyFromReturn)                                                  \
   V(DeoptimizeLazyFromThrow)                                                   \
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index 5dc42fd..003be2c 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -345,6 +345,7 @@
 
     for (int j = 0; j < _usedData; j += 2) {
       final key = _data[j];
+      final value = _data[j + 1];
 
       final fullHash = _hashCode(key);
       final hashPattern = _HashBase._hashPattern(fullHash, hashMask, size);
@@ -451,10 +452,10 @@
     }
   }
 
-  void _insert(K key, V value, int fullHash, int hashPattern, int i) {
+  void _insert(K key, V value, int hashPattern, int i) {
     if (_usedData == _data.length) {
       _rehash();
-      _set(key, value, fullHash);
+      this[key] = value;
     } else {
       assert(1 <= hashPattern && hashPattern < (1 << 32));
       final int index = _usedData >> 1;
@@ -495,12 +496,8 @@
   }
 
   void operator []=(K key, V value) {
-    final int fullHash = _hashCode(key);
-    _set(key, value, fullHash);
-  }
-
-  void _set(K key, V value, int fullHash) {
     final int size = _index.length;
+    final int fullHash = _hashCode(key);
     final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size);
     final int d =
         _findValueOrInsertPoint(key, fullHash, hashPattern, size, _index);
@@ -508,7 +505,7 @@
       _data[d] = value;
     } else {
       final int i = -d;
-      _insert(key, value, fullHash, hashPattern, i);
+      _insert(key, value, hashPattern, i);
     }
   }
 
@@ -529,7 +526,7 @@
       this[key] = value;
     } else {
       final int i = -d;
-      _insert(key, value, fullHash, hashPattern, i);
+      _insert(key, value, hashPattern, i);
     }
     return value;
   }
@@ -838,14 +835,10 @@
   }
 
   bool add(E key) {
-    final int fullHash = _hashCode(key);
-    return _add(key, fullHash);
-  }
-
-  bool _add(E key, int fullHash) {
     final int size = _index.length;
     final int sizeMask = size - 1;
     final int maxEntries = size >> 1;
+    final int fullHash = _hashCode(key);
     final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size);
     int i = _HashBase._firstProbe(fullHash, sizeMask);
     int firstDeleted = -1;
@@ -866,7 +859,7 @@
     }
     if (_usedData == _data.length) {
       _rehash();
-      _add(key, fullHash);
+      add(key);
     } else {
       final int insertionPoint = (firstDeleted >= 0) ? firstDeleted : i;
       assert(1 <= hashPattern && hashPattern < (1 << 32));
diff --git a/tools/VERSION b/tools/VERSION
index 525543e..b210de9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 92
+PRERELEASE 93
 PRERELEASE_PATCH 0
\ No newline at end of file