[vm] Fix Type.hashCode asm intrinsic with compressed pointers When loading cached hash code, asm intrinsic used LoadCompressed which results in garbage in the high 32-bits of the register. So the full register was not zero and intrinsic could return zero value in the low 32-bits. TEST=runtime/tests/vm/dart/regress_49672_test.dart Fixes https://github.com/dart-lang/sdk/issues/49672 Change-Id: Ie800dcea02db5b54bd8bf7e9df0f437f09e92932 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/305360 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/tests/vm/dart/regress_49672_test.dart b/runtime/tests/vm/dart/regress_49672_test.dart new file mode 100644 index 0000000..5976918 --- /dev/null +++ b/runtime/tests/vm/dart/regress_49672_test.dart
@@ -0,0 +1,36 @@ +// Copyright (c) 2023, 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. + +// Verifies that hash code of equal types is the same and not zero. +// Regression test for https://github.com/dart-lang/sdk/issues/49672. + +import 'package:expect/expect.dart'; + +class Foo<T> { + final brokenType = List<T>; +} + +class Bar {} + +void test1<T>() { + Expect.equals(Foo<Bar>, Foo<Bar>); + Expect.equals((Foo<Bar>).hashCode, (Foo<Bar>).hashCode); + Expect.equals(Foo<T>, Foo<Bar>); + Expect.equals((Foo<T>).hashCode, (Foo<Bar>).hashCode); +} + +void test2<T>() { + Expect.equals(Foo<Bar>, Foo<Bar>); + Expect.equals((Foo<Bar>).hashCode, (Foo<Bar>).hashCode); + Expect.equals(T, Foo<Bar>); + Expect.equals((T).hashCode, (Foo<Bar>).hashCode); +} + +void main() { + test1<Bar>(); + test2<Foo<Bar>>(); + + final a = Foo<Object>(); + Expect.isTrue(a.brokenType.hashCode != 0); +}
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc index cf18f8d..aef8a16 100644 --- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc +++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1362,8 +1362,8 @@ void AsmIntrinsifier::Type_getHashCode(Assembler* assembler, Label* normal_ir_body) { __ ldr(R0, Address(SP, 0 * target::kWordSize)); - __ LoadCompressed(R0, FieldAddress(R0, target::Type::hash_offset())); - __ cbz(normal_ir_body, R0); + __ LoadCompressedSmi(R0, FieldAddress(R0, target::Type::hash_offset())); + __ cbz(normal_ir_body, R0, kObjectBytes); __ ret(); // Hash not yet computed. __ Bind(normal_ir_body); @@ -1432,8 +1432,9 @@ void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler, Label* normal_ir_body) { __ ldr(R0, Address(SP, 0 * target::kWordSize)); - __ LoadCompressed(R0, FieldAddress(R0, target::FunctionType::hash_offset())); - __ cbz(normal_ir_body, R0); + __ LoadCompressedSmi(R0, + FieldAddress(R0, target::FunctionType::hash_offset())); + __ cbz(normal_ir_body, R0, kObjectBytes); __ ret(); // Hash not yet computed. __ Bind(normal_ir_body);
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc index d323c74..51c2a6c 100644 --- a/runtime/vm/compiler/asm_intrinsifier_x64.cc +++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -1251,10 +1251,10 @@ void AsmIntrinsifier::Type_getHashCode(Assembler* assembler, Label* normal_ir_body) { __ movq(RAX, Address(RSP, +1 * target::kWordSize)); // Type object. - __ LoadCompressed(RAX, FieldAddress(RAX, target::Type::hash_offset())); + __ LoadCompressedSmi(RAX, FieldAddress(RAX, target::Type::hash_offset())); ASSERT(kSmiTag == 0); ASSERT(kSmiTagShift == 1); - __ testq(RAX, RAX); + __ OBJ(test)(RAX, RAX); __ j(ZERO, normal_ir_body, Assembler::kNearJump); __ ret(); __ Bind(normal_ir_body); @@ -1325,11 +1325,11 @@ void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler, Label* normal_ir_body) { __ movq(RAX, Address(RSP, +1 * target::kWordSize)); // FunctionType object. - __ LoadCompressed(RAX, - FieldAddress(RAX, target::FunctionType::hash_offset())); + __ LoadCompressedSmi(RAX, + FieldAddress(RAX, target::FunctionType::hash_offset())); ASSERT(kSmiTag == 0); ASSERT(kSmiTagShift == 1); - __ testq(RAX, RAX); + __ OBJ(test)(RAX, RAX); __ j(ZERO, normal_ir_body, Assembler::kNearJump); __ ret(); __ Bind(normal_ir_body);