Version 2.14.0-295.0.dev
Merge commit '0f948691d2d995baf7b7afadba332940f6245d02' into 'dev'
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index af7acb1..7e5c738 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4766,6 +4766,166 @@
EXPECT(result.IsIdenticalTo(expected));
}
+const uint32_t kCalculateCanonizalizeHash = 0;
+
+// Checks that the .hashCode equals the VM CanonicalizeHash() for keys in
+// constant maps.
+//
+// Expects a script with a method named `value`.
+//
+// If `hashcode_canonicalize_vm` is non-zero, the VM CanonicalizeHash()
+// is not executed but the provided value is used.
+static bool HashCodeEqualsCanonicalizeHash(
+ const char* value_script,
+ uint32_t hashcode_canonicalize_vm = kCalculateCanonizalizeHash,
+ bool check_identity = true,
+ bool check_hashcode = true,
+ bool print_failure = true) {
+ auto kScriptChars = Utils::CStringUniquePtr(
+ OS::SCreate(nullptr,
+ "%s"
+ "\n"
+ "valueHashCode() {\n"
+ " return value().hashCode;\n"
+ "}\n"
+ "\n"
+ "valueIdentityHashCode() {\n"
+ " return identityHashCode(value());\n"
+ "}\n",
+ value_script),
+ std::free);
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars.get(), nullptr);
+ EXPECT_VALID(lib);
+ Dart_Handle value_result = Dart_Invoke(lib, NewString("value"), 0, nullptr);
+ EXPECT_VALID(value_result);
+ Dart_Handle hashcode_result;
+ if (check_hashcode) {
+ hashcode_result = Dart_Invoke(lib, NewString("valueHashCode"), 0, nullptr);
+ EXPECT_VALID(hashcode_result);
+ }
+ Dart_Handle identity_hashcode_result =
+ Dart_Invoke(lib, NewString("valueIdentityHashCode"), 0, nullptr);
+ EXPECT_VALID(identity_hashcode_result);
+
+ TransitionNativeToVM transition(Thread::Current());
+
+ const auto& value_dart = Instance::CheckedHandle(
+ Thread::Current()->zone(), Api::UnwrapHandle(value_result));
+ int64_t hashcode_dart;
+ if (check_hashcode) {
+ hashcode_dart =
+ Integer::Cast(Object::Handle(Api::UnwrapHandle(hashcode_result)))
+ .AsInt64Value();
+ }
+ const int64_t identity_hashcode_dart =
+ Integer::Cast(Object::Handle(Api::UnwrapHandle(identity_hashcode_result)))
+ .AsInt64Value();
+ if (hashcode_canonicalize_vm == 0) {
+ hashcode_canonicalize_vm = Instance::Cast(value_dart).CanonicalizeHash();
+ }
+
+ bool success = true;
+
+ if (check_hashcode) {
+ success &= hashcode_dart == hashcode_canonicalize_vm;
+ }
+ if (check_identity) {
+ success &= identity_hashcode_dart == hashcode_canonicalize_vm;
+ }
+
+ if (!success && print_failure) {
+ LogBlock lb;
+ THR_Print(
+ "Dart hashCode or Dart identityHashCode does not equal VM "
+ "CanonicalizeHash for %s\n",
+ value_dart.ToCString());
+ THR_Print("Dart hashCode %" Px64 " %" Pd64 "\n", hashcode_dart,
+ hashcode_dart);
+ THR_Print("Dart identityHashCode %" Px64 " %" Pd64 "\n",
+ identity_hashcode_dart, identity_hashcode_dart);
+ THR_Print("VM CanonicalizeHash %" Px32 " %" Pd32 "\n",
+ hashcode_canonicalize_vm, hashcode_canonicalize_vm);
+ }
+
+ return success;
+}
+
+TEST_CASE(HashCode_Double) {
+ const char* kScript =
+ "value() {\n"
+ " return 1.0;\n"
+ "}\n";
+ // Double VM CanonicalizeHash is not equal to hashCode, because doubles
+ // cannot be used as keys in constant sets and maps. However, doubles
+ // _can_ be used for lookups in which case they are equal to their integer
+ // value.
+ const uint32_t kInt1HashCode = 1;
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kInt1HashCode));
+}
+
+TEST_CASE(HashCode_Mint) {
+ const char* kScript =
+ "value() {\n"
+ " return 0x8000000;\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript));
+}
+
+TEST_CASE(HashCode_Null) {
+ const char* kScript =
+ "value() {\n"
+ " return null;\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript));
+}
+
+TEST_CASE(HashCode_Smi) {
+ const char* kScript =
+ "value() {\n"
+ " return 123;\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript));
+}
+
+TEST_CASE(HashCode_String) {
+ const char* kScript =
+ "value() {\n"
+ " return 'asdf';\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript));
+}
+
+TEST_CASE(HashCode_True) {
+ const char* kScript =
+ "value() {\n"
+ " return true;\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript));
+}
+
+TEST_CASE(HashCode_Type_Dynamic) {
+ const char* kScript =
+ "const type = dynamic;\n"
+ "\n"
+ "value() {\n"
+ " return type;\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kCalculateCanonizalizeHash,
+ /*check_identity=*/false));
+}
+
+TEST_CASE(HashCode_Type_Int) {
+ const char* kScript =
+ "const type = int;\n"
+ "\n"
+ "value() {\n"
+ " return type;\n"
+ "}\n";
+ EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kCalculateCanonizalizeHash,
+ /*check_identity=*/false));
+}
+
TEST_CASE(LinkedHashMap_iteration) {
const char* kScript =
"makeMap() {\n"
diff --git a/tools/VERSION b/tools/VERSION
index 13201df..4dd96b4 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 294
+PRERELEASE 295
PRERELEASE_PATCH 0
\ No newline at end of file