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