[vm] Refactor generation of identity hashes.

Generating identity hashes from the runtime no longer calls into Dart. On 32-bit systems, generating identity hashes from Dart now does only one runtime transition.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/47873
Change-Id: Ib21156cb05706f81744eb4e5ccb644f40aa84c96
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/222326
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/front_end/testcases/general/invalid_operator.dart.weak.expect b/pkg/front_end/testcases/general/invalid_operator.dart.weak.expect
index c3f1e06..1bababf 100644
--- a/pkg/front_end/testcases/general/invalid_operator.dart.weak.expect
+++ b/pkg/front_end/testcases/general/invalid_operator.dart.weak.expect
@@ -564,35 +564,35 @@
 // Try adding explicit types.
 //   operator ==<T>(a) => true;
 //            ^^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is one of the overridden members.
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is one of the overridden members.
 //   external bool operator ==(Object other);
 //                          ^^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:6:12: Error: The method 'Operators1.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   operator ==() => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:27:12: Error: The method 'Operators2.==' has more required arguments than those of overridden method 'Object.=='.
 //   operator ==(a, b) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:71:12: Error: The method 'Operators4.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   operator ==({a}) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:137:12: Error: Declared type variables of 'Operators7.==' doesn't match those on overridden method 'Object.=='.
 //   operator ==<T>(a) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/front_end/testcases/general/invalid_operator.dart.weak.modular.expect b/pkg/front_end/testcases/general/invalid_operator.dart.weak.modular.expect
index c3f1e06..1bababf 100644
--- a/pkg/front_end/testcases/general/invalid_operator.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/invalid_operator.dart.weak.modular.expect
@@ -564,35 +564,35 @@
 // Try adding explicit types.
 //   operator ==<T>(a) => true;
 //            ^^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is one of the overridden members.
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is one of the overridden members.
 //   external bool operator ==(Object other);
 //                          ^^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:6:12: Error: The method 'Operators1.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   operator ==() => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:27:12: Error: The method 'Operators2.==' has more required arguments than those of overridden method 'Object.=='.
 //   operator ==(a, b) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:71:12: Error: The method 'Operators4.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   operator ==({a}) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:137:12: Error: Declared type variables of 'Operators7.==' doesn't match those on overridden method 'Object.=='.
 //   operator ==<T>(a) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/front_end/testcases/general/invalid_operator.dart.weak.outline.expect b/pkg/front_end/testcases/general/invalid_operator.dart.weak.outline.expect
index c1ee228..c9f7e40 100644
--- a/pkg/front_end/testcases/general/invalid_operator.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/invalid_operator.dart.weak.outline.expect
@@ -564,35 +564,35 @@
 // Try adding explicit types.
 //   operator ==<T>(a) => true;
 //            ^^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is one of the overridden members.
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is one of the overridden members.
 //   external bool operator ==(Object other);
 //                          ^^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:6:12: Error: The method 'Operators1.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   operator ==() => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:27:12: Error: The method 'Operators2.==' has more required arguments than those of overridden method 'Object.=='.
 //   operator ==(a, b) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:71:12: Error: The method 'Operators4.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   operator ==({a}) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
 // pkg/front_end/testcases/general/invalid_operator.dart:137:12: Error: Declared type variables of 'Operators7.==' doesn't match those on overridden method 'Object.=='.
 //   operator ==<T>(a) => true;
 //            ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/front_end/testcases/nnbd/issue42603.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42603.dart.strong.expect
index 1717f29..7d802ac 100644
--- a/pkg/front_end/testcases/nnbd/issue42603.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/issue42603.dart.strong.expect
@@ -9,7 +9,7 @@
 // pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   bool operator ==() => true;
 //                 ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/front_end/testcases/nnbd/issue42603.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42603.dart.weak.expect
index 1717f29..7d802ac 100644
--- a/pkg/front_end/testcases/nnbd/issue42603.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/issue42603.dart.weak.expect
@@ -9,7 +9,7 @@
 // pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   bool operator ==() => true;
 //                 ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/front_end/testcases/nnbd/issue42603.dart.weak.modular.expect b/pkg/front_end/testcases/nnbd/issue42603.dart.weak.modular.expect
index 1717f29..7d802ac 100644
--- a/pkg/front_end/testcases/nnbd/issue42603.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/nnbd/issue42603.dart.weak.modular.expect
@@ -9,7 +9,7 @@
 // pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   bool operator ==() => true;
 //                 ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/front_end/testcases/nnbd/issue42603.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue42603.dart.weak.outline.expect
index f1a33e9..390818a 100644
--- a/pkg/front_end/testcases/nnbd/issue42603.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/nnbd/issue42603.dart.weak.outline.expect
@@ -9,7 +9,7 @@
 // pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
 //   bool operator ==() => true;
 //                 ^
-// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
+// sdk/lib/_internal/vm/lib/object_patch.dart:21:26: Context: This is the overridden method ('==').
 //   external bool operator ==(Object other);
 //                          ^
 //
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
index 8964972..ebc13da 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
@@ -22,6 +22,6 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3305,getterSelectorId:3306]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3303,getterSelectorId:3304]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
     return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
index 7251a55..d0ed61e 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
@@ -51,6 +51,6 @@
   synthetic constructor •() → self::ConstClass
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3309,getterSelectorId:3310]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3307,getterSelectorId:3308]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
     return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
 }
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index f8e903e..2b7a470 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -48,20 +48,14 @@
   // Please note that no handle is created for the argument.
   // This is safe since the argument is only used in a tail call.
   // The performance benefit is more than 5% when using hashCode.
-  return Smi::New(GetHash(isolate, arguments->NativeArgAt(0)));
-}
+  intptr_t hash = GetHash(isolate, arguments->NativeArgAt(0));
+  if (LIKELY(hash != 0)) {
+    return Smi::New(hash);
+  }
 
-DEFINE_NATIVE_ENTRY(Object_setHashIfNotSetYet, 0, 2) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Smi, hash, arguments->NativeArgAt(1));
-#if defined(HASH_IN_OBJECT_HEADER)
-  return Smi::New(
-      Object::SetCachedHashIfNotSet(arguments->NativeArgAt(0), hash.Value()));
-#else
   const Instance& instance =
       Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
-  Heap* heap = thread->heap();
-  return Smi::New(heap->SetHashIfNotSet(instance.ptr(), hash.Value()));
-#endif
+  return instance.IdentityHashCode(arguments->thread());
 }
 
 DEFINE_NATIVE_ENTRY(Object_toString, 0, 1) {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index adade03..50e587f 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -18,7 +18,6 @@
   V(DartAsync_fatal, 1)                                                        \
   V(Object_equals, 2)                                                          \
   V(Object_getHash, 1)                                                         \
-  V(Object_setHashIfNotSetYet, 2)                                              \
   V(Object_toString, 1)                                                        \
   V(Object_runtimeType, 1)                                                     \
   V(Object_haveSameRuntimeType, 2)                                             \
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index b61046d..e811039 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1548,11 +1548,6 @@
   UNREACHABLE();
 }
 
-void AsmIntrinsifier::Object_setHashIfNotSetYet(Assembler* assembler,
-                                                Label* normal_ir_body) {
-  UNREACHABLE();
-}
-
 void AsmIntrinsifier::StringBaseCharAt(Assembler* assembler,
                                        Label* normal_ir_body) {
   Label try_two_byte_string;
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index b6796b5..f9c178a 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1578,21 +1578,37 @@
   __ Bind(normal_ir_body);
 }
 
+// Keep in sync with Instance::IdentityHashCode.
+// Note int and double never reach here because they override _identityHashCode.
+// Special cases are also not needed for null or bool because they were pre-set
+// during VM isolate finalization.
 void AsmIntrinsifier::Object_getHash(Assembler* assembler,
                                      Label* normal_ir_body) {
-  __ ldr(R0, Address(SP, 0 * target::kWordSize));
-  __ ldr(R0, FieldAddress(R0, target::String::hash_offset(), kFourBytes),
+  Label not_yet_computed;
+  __ ldr(R0, Address(SP, 0 * target::kWordSize));  // Object.
+  __ ldr(R0,
+         FieldAddress(R0,
+                      target::Object::tags_offset() +
+                          target::UntaggedObject::kHashTagPos / kBitsPerByte,
+                      kFourBytes),
          kUnsignedFourBytes);
+  __ cbz(&not_yet_computed, R0);
   __ SmiTag(R0);
   __ ret();
-}
 
-void AsmIntrinsifier::Object_setHashIfNotSetYet(Assembler* assembler,
-                                                Label* normal_ir_body) {
-  __ ldp(/*Value=*/R1, /*Object=*/R0, Address(SP, 0, Address::PairOffset));
-  // R0: Untagged address of header word (ldxr/stxr do not support offsets).
+  __ Bind(&not_yet_computed);
+  __ LoadFromOffset(R1, THR, target::Thread::random_offset());
+  __ AndImmediate(R2, R1, 0xffffffff);  // state_lo
+  __ LsrImmediate(R3, R1, 32);          // state_hi
+  __ LoadImmediate(R1, 0xffffda61);     // A
+  __ mul(R1, R1, R2);
+  __ add(R1, R1, Operand(R3));  // new_state = (A * state_lo) + state_hi
+  __ StoreToOffset(R1, THR, target::Thread::random_offset());
+  __ AndImmediate(R1, R1, 0x3fffffff);
+  __ cbz(&not_yet_computed, R1);
+
+  __ ldr(R0, Address(SP, 0 * target::kWordSize));  // Object.
   __ sub(R0, R0, Operand(kHeapObjectTag));
-  __ SmiUntag(R1);
   __ LslImmediate(R3, R1, target::UntaggedObject::kHashTagPos);
 
   Label retry, already_set_in_r4;
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index 0c58ca7..341c285 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -1555,11 +1555,6 @@
   UNREACHABLE();
 }
 
-void AsmIntrinsifier::Object_setHashIfNotSetYet(Assembler* assembler,
-                                                Label* normal_ir_body) {
-  UNREACHABLE();
-}
-
 void AsmIntrinsifier::StringBaseCharAt(Assembler* assembler,
                                        Label* normal_ir_body) {
   Label try_two_byte_string;
diff --git a/runtime/vm/compiler/asm_intrinsifier_test.cc b/runtime/vm/compiler/asm_intrinsifier_test.cc
index e5678ee..fb112f1 100644
--- a/runtime/vm/compiler/asm_intrinsifier_test.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_test.cc
@@ -10,78 +10,4 @@
 
 namespace dart {
 
-static intptr_t GetHash(Isolate* isolate, const ObjectPtr obj) {
-#if defined(HASH_IN_OBJECT_HEADER)
-  return Object::GetCachedHash(obj);
-#else
-  Heap* heap = isolate->group()->heap();
-  ASSERT(obj->IsDartInstance());
-  return heap->GetHash(obj);
-#endif
-}
-
-ISOLATE_UNIT_TEST_CASE(AsmIntrinsifier_SetHashIfNotSetYet) {
-  auto I = Isolate::Current();
-  const auto& corelib = Library::Handle(Library::CoreLibrary());
-  const auto& name = String::Handle(String::New("_setHashIfNotSetYet"));
-  const auto& symbol = String::Handle(Symbols::New(thread, name));
-
-  const auto& function =
-      Function::Handle(corelib.LookupFunctionAllowPrivate(symbol));
-  const auto& object_class =
-      Class::Handle(corelib.LookupClass(Symbols::Object()));
-
-  auto& smi0 = Smi::Handle(Smi::New(0));
-  auto& smi21 = Smi::Handle(Smi::New(21));
-  auto& smi42 = Smi::Handle(Smi::New(42));
-  const auto& obj = Object::Handle(Instance::New(object_class));
-  const auto& args = Array::Handle(Array::New(2));
-
-  const auto& args_descriptor_array =
-      Array::Handle(ArgumentsDescriptor::NewBoxed(0, 2, Array::empty_array()));
-
-  // Initialized to 0
-  EXPECT_EQ(smi0.ptr(), Smi::New(GetHash(I, obj.ptr())));
-
-  // Lazily set to 42 on first call.
-  args.SetAt(0, obj);
-  args.SetAt(1, smi42);
-  EXPECT_EQ(smi42.ptr(),
-            DartEntry::InvokeFunction(function, args, args_descriptor_array));
-  EXPECT_EQ(smi42.ptr(), Smi::New(GetHash(I, obj.ptr())));
-
-  // Stays at 42 on subsequent calls.
-  args.SetAt(0, obj);
-  args.SetAt(1, smi21);
-  EXPECT_EQ(smi42.ptr(),
-            DartEntry::InvokeFunction(function, args, args_descriptor_array));
-  EXPECT_EQ(smi42.ptr(), Smi::New(GetHash(I, obj.ptr())));
-
-  // We test setting the maximum value our core libraries would use when
-  // installing an identity hash code (see
-  // sdk/lib/_internal/vm/lib/object_patch.dart:Object._objectHashCode)
-  //
-  // This value is representable as a positive Smi on all architectures (even
-  // compressed pointers).
-  const auto& smiMax = Smi::Handle(Smi::New(0x40000000 - 1));
-  const auto& obj2 = Object::Handle(Instance::New(object_class));
-
-  // Initialized to 0
-  EXPECT_EQ(smi0.ptr(), Smi::New(GetHash(I, obj2.ptr())));
-
-  // Lazily set to smiMax first call.
-  args.SetAt(0, obj2);
-  args.SetAt(1, smiMax);
-  EXPECT_EQ(smiMax.ptr(),
-            DartEntry::InvokeFunction(function, args, args_descriptor_array));
-  EXPECT_EQ(smiMax.ptr(), Smi::New(GetHash(I, obj2.ptr())));
-
-  // Stays at smiMax on subsequent calls.
-  args.SetAt(0, obj2);
-  args.SetAt(1, smi21);
-  EXPECT_EQ(smiMax.ptr(),
-            DartEntry::InvokeFunction(function, args, args_descriptor_array));
-  EXPECT_EQ(smiMax.ptr(), Smi::New(GetHash(I, obj2.ptr())));
-}
-
 }  // namespace dart
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index c4e02a9..e2f7b24 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -1452,21 +1452,35 @@
   __ Bind(normal_ir_body);
 }
 
+// Keep in sync with Instance::IdentityHashCode.
+// Note int and double never reach here because they override _identityHashCode.
+// Special cases are also not needed for null or bool because they were pre-set
+// during VM isolate finalization.
 void AsmIntrinsifier::Object_getHash(Assembler* assembler,
                                      Label* normal_ir_body) {
+  Label not_yet_computed;
   __ movq(RAX, Address(RSP, +1 * target::kWordSize));  // Object.
-  __ movl(RAX, FieldAddress(RAX, target::String::hash_offset()));
+  __ movl(RAX, FieldAddress(RAX, target::Object::tags_offset() +
+                                     target::UntaggedObject::kHashTagPos /
+                                         kBitsPerByte));
+  __ cmpl(RAX, Immediate(0));
+  __ j(EQUAL, &not_yet_computed, Assembler::kNearJump);
   __ SmiTag(RAX);
   __ ret();
-}
 
-void AsmIntrinsifier::Object_setHashIfNotSetYet(Assembler* assembler,
-                                                Label* normal_ir_body) {
-  ASSERT(target::String::hash_offset() == 4);
+  __ Bind(&not_yet_computed);
+  __ movq(RCX, Address(THR, target::Thread::random_offset()));
+  __ movq(RBX, RCX);
+  __ andq(RCX, Immediate(0xffffffff));   // state_lo
+  __ shrq(RBX, Immediate(32));           // state_hi
+  __ imulq(RCX, Immediate(0xffffda61));  // A
+  __ addq(RCX, RBX);                     // new_state = (A* state_lo) + state_hi
+  __ movq(Address(THR, target::Thread::random_offset()), RCX);
+  __ andq(RCX, Immediate(0x3fffffff));
+  __ cmpl(RCX, Immediate(0));
+  __ j(EQUAL, &not_yet_computed);
 
-  __ movq(RBX, Address(RSP, +2 * target::kWordSize));  // Object.
-  __ movq(RCX, Address(RSP, +1 * target::kWordSize));  // Value.
-  __ SmiUntag(RCX);
+  __ movq(RBX, Address(RSP, +1 * target::kWordSize));  // Object.
   __ MoveRegister(RDX, RCX);
   __ shlq(RDX, Immediate(32));
 
diff --git a/runtime/vm/compiler/intrinsifier.cc b/runtime/vm/compiler/intrinsifier.cc
index 4ba80d9f..072e8ca 100644
--- a/runtime/vm/compiler/intrinsifier.cc
+++ b/runtime/vm/compiler/intrinsifier.cc
@@ -275,9 +275,7 @@
   // identity hash is not stored in the header of the object.  We
   // therefore don't intrinsify them, falling back on the native C++
   // implementations.
-  if (function.recognized_kind() == MethodRecognizer::kObject_getHash ||
-      function.recognized_kind() ==
-          MethodRecognizer::kObject_setHashIfNotSetYet) {
+  if (function.recognized_kind() == MethodRecognizer::kObject_getHash) {
     return false;
   }
 #endif
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 2d60271..e2f2083 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -290,7 +290,6 @@
   V(_FunctionType, get:hashCode, FunctionType_getHashCode, 0x75e0d454)         \
   V(_FunctionType, ==, FunctionType_equality, 0x465868ae)                      \
   V(::, _getHash, Object_getHash, 0xc60ff758)                                  \
-  V(::, _setHashIfNotSetYet, Object_setHashIfNotSetYet, 0x4e17c2f5)            \
 
 #define CORE_INTEGER_LIB_INTRINSIC_LIST(V)                                     \
   V(_IntegerImplementation, >, Integer_greaterThan, 0xf741693b)                \
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index abb824d..bc2daf8 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -99,7 +99,7 @@
 
 intptr_t ObjectHash(const Object& obj) {
   if (obj.IsNull()) {
-    return 2011;
+    return kNullIdentityHash;
   }
   if (obj.IsInstance()) {
     return Instance::Cast(obj).CanonicalizeHash();
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 8d9a7a1..1cdca3d 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1192,6 +1192,8 @@
   THREAD_XMM_CONSTANT_LIST(DECLARE_CONSTANT_OFFSET_GETTER)
 #undef DECLARE_CONSTANT_OFFSET_GETTER
 
+  static word random_offset();
+
   static word OffsetFromThread(const dart::Object& object);
   static intptr_t OffsetFromThread(const dart::RuntimeEntry* runtime_entry);
 };
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 2a33ea5..5c98bc9 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -286,7 +286,7 @@
     Thread_call_to_runtime_entry_point_offset = 276;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 144;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 808;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 816;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
@@ -332,7 +332,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     788;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 812;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 820;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -417,9 +417,10 @@
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 780;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 784;
+static constexpr dart::compiler::target::word Thread_random_offset = 800;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 328;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 800;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 808;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -851,7 +852,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1616;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1624;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -898,7 +899,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -984,9 +985,10 @@
     1560;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1600;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1608;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -1416,7 +1418,7 @@
     Thread_call_to_runtime_entry_point_offset = 276;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 144;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 776;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 784;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
@@ -1462,7 +1464,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     756;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 780;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 788;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -1547,9 +1549,10 @@
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 748;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 752;
+static constexpr dart::compiler::target::word Thread_random_offset = 768;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 328;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 768;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 776;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -1978,7 +1981,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1680;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1688;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -2025,7 +2028,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -2111,9 +2114,10 @@
     1624;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1664;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1672;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -2547,7 +2551,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1616;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1624;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -2594,7 +2598,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -2680,9 +2684,10 @@
     1560;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1600;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1608;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -3115,7 +3120,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1680;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1688;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -3162,7 +3167,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -3248,9 +3253,10 @@
     1624;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1664;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1672;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -3677,7 +3683,7 @@
     Thread_call_to_runtime_entry_point_offset = 276;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 144;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 808;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 816;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
@@ -3723,7 +3729,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     788;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 812;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 820;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -3808,9 +3814,10 @@
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 780;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 784;
+static constexpr dart::compiler::target::word Thread_random_offset = 800;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 328;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 800;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 808;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -4236,7 +4243,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1616;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1624;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -4283,7 +4290,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -4369,9 +4376,10 @@
     1560;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1600;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1608;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -4795,7 +4803,7 @@
     Thread_call_to_runtime_entry_point_offset = 276;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 144;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 776;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 784;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
@@ -4841,7 +4849,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     756;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 780;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 788;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -4926,9 +4934,10 @@
 static constexpr dart::compiler::target::word Thread_callback_code_offset = 748;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 752;
+static constexpr dart::compiler::target::word Thread_random_offset = 768;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 328;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 768;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 776;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -5351,7 +5360,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1680;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1688;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -5398,7 +5407,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -5484,9 +5493,10 @@
     1624;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1664;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1672;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -5914,7 +5924,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1616;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1624;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -5961,7 +5971,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -6047,9 +6057,10 @@
     1560;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1600;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1608;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -6476,7 +6487,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1680;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1688;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -6523,7 +6534,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -6609,9 +6620,10 @@
     1624;
 static constexpr dart::compiler::target::word
     Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     Thread_jump_to_frame_entry_point_offset = 632;
-static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1664;
+static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 1672;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
     0;
 static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@@ -7078,7 +7090,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 144;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    808;
+    816;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
@@ -7126,7 +7138,7 @@
     AOT_Thread_exit_through_ffi_offset = 788;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    812;
+    820;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
 static constexpr dart::compiler::target::word
@@ -7216,10 +7228,11 @@
     780;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 784;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 800;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 328;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    800;
+    808;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -7707,7 +7720,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1616;
+    1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -7755,7 +7768,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -7846,10 +7859,11 @@
     1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1600;
+    1608;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -8342,7 +8356,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1680;
+    1688;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -8390,7 +8404,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -8481,10 +8495,11 @@
     1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1664;
+    1672;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -8974,7 +8989,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1616;
+    1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -9022,7 +9037,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -9113,10 +9128,11 @@
     1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1600;
+    1608;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -9605,7 +9621,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1680;
+    1688;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -9653,7 +9669,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -9744,10 +9760,11 @@
     1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1664;
+    1672;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -10232,7 +10249,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 144;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    808;
+    816;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
@@ -10280,7 +10297,7 @@
     AOT_Thread_exit_through_ffi_offset = 788;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    812;
+    820;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
 static constexpr dart::compiler::target::word
@@ -10370,10 +10387,11 @@
     780;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 784;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 800;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 328;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    800;
+    808;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -10854,7 +10872,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1616;
+    1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -10902,7 +10920,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -10993,10 +11011,11 @@
     1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1600;
+    1608;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -11482,7 +11501,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1680;
+    1688;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -11530,7 +11549,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -11621,10 +11640,11 @@
     1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1664;
+    1672;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -12107,7 +12127,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1616;
+    1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -12155,7 +12175,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1624;
+    1632;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -12246,10 +12266,11 @@
     1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1568;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1600;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1600;
+    1608;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
@@ -12731,7 +12752,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 264;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1680;
+    1688;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
@@ -12779,7 +12800,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -12870,10 +12891,11 @@
     1624;
 static constexpr dart::compiler::target::word
     AOT_Thread_callback_stack_return_offset = 1632;
+static constexpr dart::compiler::target::word AOT_Thread_random_offset = 1664;
 static constexpr dart::compiler::target::word
     AOT_Thread_jump_to_frame_entry_point_offset = 632;
 static constexpr dart::compiler::target::word AOT_Thread_tsan_utils_offset =
-    1664;
+    1672;
 static constexpr dart::compiler::target::word
     AOT_TsanUtils_setjmp_function_offset = 0;
 static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index d0264eb..71cc428 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -286,6 +286,7 @@
   FIELD(Thread, heap_base_offset)                                              \
   FIELD(Thread, callback_code_offset)                                          \
   FIELD(Thread, callback_stack_return_offset)                                  \
+  FIELD(Thread, random_offset)                                                 \
   FIELD(Thread, jump_to_frame_entry_point_offset)                              \
   FIELD(Thread, tsan_utils_offset)                                             \
   FIELD(TsanUtils, setjmp_function_offset)                                     \
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 7041084..46df59f 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -676,24 +676,6 @@
   return result.ptr();
 }
 
-// On success, returns an InstancePtr.  On failure, an ErrorPtr.
-ObjectPtr DartLibraryCalls::IdentityHashCode(const Instance& object) {
-  const int kNumArguments = 1;
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  const Library& libcore = Library::Handle(zone, Library::CoreLibrary());
-  ASSERT(!libcore.IsNull());
-  const Function& function = Function::Handle(
-      zone, libcore.LookupFunctionAllowPrivate(Symbols::identityHashCode()));
-  ASSERT(!function.IsNull());
-  const Array& args = Array::Handle(zone, Array::New(kNumArguments));
-  args.SetAt(0, object);
-  const Object& result =
-      Object::Handle(zone, DartEntry::InvokeFunction(function, args));
-  ASSERT(result.IsInstance() || result.IsError());
-  return result.ptr();
-}
-
 ObjectPtr DartLibraryCalls::LookupHandler(Dart_Port port_id) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 6ec9067..4f650a8 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -285,9 +285,6 @@
   // On success, returns an InstancePtr. On failure, an ErrorPtr.
   static ObjectPtr Equals(const Instance& left, const Instance& right);
 
-  // On success, returns an InstancePtr. On failure, an ErrorPtr.
-  static ObjectPtr IdentityHashCode(const Instance& object);
-
   // Returns the handler if one has been registered for this port id.
   static ObjectPtr LookupHandler(Dart_Port port_id);
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index df10c58..b37de90 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1344,8 +1344,13 @@
         // Some classes have identity hash codes that depend on their contents,
         // not per object.
         ASSERT(!obj->IsStringInstance());
-        if (!obj->IsMint() && !obj->IsDouble() && !obj->IsRawNull() &&
-            !obj->IsBool()) {
+        if (obj == Object::null()) {
+          Object::SetCachedHashIfNotSet(obj, kNullIdentityHash);
+        } else if (obj == Object::bool_true().ptr()) {
+          Object::SetCachedHashIfNotSet(obj, kTrueIdentityHash);
+        } else if (obj == Object::bool_false().ptr()) {
+          Object::SetCachedHashIfNotSet(obj, kFalseIdentityHash);
+        } else if (!obj->IsMint() && !obj->IsDouble()) {
           counter_ += 2011;  // The year Dart was announced and a prime.
           counter_ &= 0x3fffffff;
           if (counter_ == 0) counter_++;
@@ -9522,15 +9527,6 @@
   return target.ptr();
 }
 
-intptr_t Function::ComputeClosureHash() const {
-  ASSERT(IsClosureFunction());
-  const Class& cls = Class::Handle(Owner());
-  uintptr_t result = String::Handle(name()).Hash();
-  result += String::Handle(InternalSignature()).Hash();
-  result += String::Handle(cls.Name()).Hash();
-  return result;
-}
-
 void FunctionType::Print(NameVisibility name_visibility,
                          BaseTextBuffer* printer) const {
   if (IsNull()) {
@@ -18995,8 +18991,45 @@
   return DartLibraryCalls::HashCode(*this);
 }
 
-ObjectPtr Instance::IdentityHashCode() const {
-  return DartLibraryCalls::IdentityHashCode(*this);
+// Keep in sync with AsmIntrinsifier::Object_getHash.
+IntegerPtr Instance::IdentityHashCode(Thread* thread) const {
+  if (IsInteger()) return Integer::Cast(*this).ptr();
+
+#if defined(HASH_IN_OBJECT_HEADER)
+  intptr_t hash = Object::GetCachedHash(ptr());
+#else
+  intptr_t hash = thread->heap()->GetHash(ptr());
+#endif
+  if (hash == 0) {
+    if (IsNull()) {
+      hash = kNullIdentityHash;
+    } else if (IsBool()) {
+      hash = Bool::Cast(*this).value() ? kTrueIdentityHash : kFalseIdentityHash;
+    } else if (IsDouble()) {
+      double val = Double::Cast(*this).value();
+      if ((val >= kMinInt64RepresentableAsDouble) &&
+          (val <= kMaxInt64RepresentableAsDouble)) {
+        int64_t ival = static_cast<int64_t>(val);
+        if (static_cast<double>(ival) == val) {
+          return Integer::New(ival);
+        }
+      }
+
+      uint64_t uval = bit_cast<uint64_t>(val);
+      hash = ((uval >> 32) ^ (uval)) & kSmiMax;
+    } else {
+      do {
+        hash = thread->random()->NextUInt32() & 0x3FFFFFFF;
+      } while (hash == 0);
+    }
+
+#if defined(HASH_IN_OBJECT_HEADER)
+    hash = Object::SetCachedHashIfNotSet(ptr(), hash);
+#else
+    hash = thread->heap()->SetHashIfNotSet(ptr(), hash);
+#endif
+  }
+  return Smi::New(hash);
 }
 
 bool Instance::CanonicalizeEquals(const Instance& other) const {
@@ -19058,7 +19091,7 @@
 
 uint32_t Instance::CanonicalizeHash() const {
   if (GetClassId() == kNullCid) {
-    return 2011;  // Matches null_patch.dart.
+    return kNullIdentityHash;
   }
   Thread* thread = Thread::Current();
   uint32_t hash = thread->heap()->GetCanonicalHash(ptr());
@@ -25457,7 +25490,7 @@
     // Implicit instance closures are not unique, so combine function's hash
     // code, delayed type arguments hash code (if generic), and identityHashCode
     // of cached receiver.
-    result = static_cast<uint32_t>(func.ComputeClosureHash());
+    result = static_cast<uint32_t>(func.Hash());
     if (func.IsGeneric()) {
       const TypeArguments& delayed_type_args =
           TypeArguments::Handle(zone, delayed_type_arguments());
@@ -25466,23 +25499,15 @@
     const Context& context = Context::Handle(zone, this->context());
     const Instance& receiver =
         Instance::Handle(zone, Instance::RawCast(context.At(0)));
-    const Object& receiverHash =
-        Object::Handle(zone, receiver.IdentityHashCode());
-    if (receiverHash.IsError()) {
-      Exceptions::PropagateError(Error::Cast(receiverHash));
-      UNREACHABLE();
-    }
-    result = CombineHashes(
-        result, Integer::Cast(receiverHash).AsTruncatedUint32Value());
+    const Integer& receiverHash =
+        Integer::Handle(zone, receiver.IdentityHashCode(thread));
+    result = CombineHashes(result, receiverHash.AsTruncatedUint32Value());
   } else {
     // Explicit closures and implicit static closures are unique,
     // so identityHashCode of closure object is good enough.
-    const Object& identityHash = Object::Handle(zone, this->IdentityHashCode());
-    if (identityHash.IsError()) {
-      Exceptions::PropagateError(Error::Cast(identityHash));
-      UNREACHABLE();
-    }
-    result = Integer::Cast(identityHash).AsTruncatedUint32Value();
+    const Integer& identityHash =
+        Integer::Handle(zone, this->IdentityHashCode(thread));
+    result = identityHash.AsTruncatedUint32Value();
   }
   return FinalizeHash(result, String::kHashBits);
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ba6e15d..591c5a1 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2947,8 +2947,6 @@
   // invalid (e.g., mismatched argument shapes after a reload).
   FunctionPtr ImplicitClosureTarget(Zone* zone) const;
 
-  intptr_t ComputeClosureHash() const;
-
   FunctionPtr ForwardingTarget() const;
   void SetForwardingTarget(const Function& target) const;
 
@@ -7517,7 +7515,7 @@
   virtual ObjectPtr HashCode() const;
 
   // Equivalent to invoking identityHashCode with this instance.
-  ObjectPtr IdentityHashCode() const;
+  IntegerPtr IdentityHashCode(Thread* thread) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(UntaggedInstance));
@@ -10065,6 +10063,11 @@
   friend class Symbols;
 };
 
+// Matches null_patch.dart / bool_patch.dart.
+static constexpr intptr_t kNullIdentityHash = 2011;
+static constexpr intptr_t kTrueIdentityHash = 1231;
+static constexpr intptr_t kFalseIdentityHash = 1237;
+
 // Class Bool implements Dart core class bool.
 class Bool : public Instance {
  public:
@@ -10083,7 +10086,7 @@
   }
 
   virtual uint32_t CanonicalizeHash() const {
-    return ptr() == True().ptr() ? 1231 : 1237;
+    return ptr() == True().ptr() ? kTrueIdentityHash : kFalseIdentityHash;
   }
 
  private:
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 50640ad..880bdde 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -441,7 +441,6 @@
   V(current_position, ":current_position")                                     \
   V(dynamic_assert_assignable_stc_check,                                       \
     ":dynamic_assert_assignable_stc_check")                                    \
-  V(identityHashCode, "identityHashCode")                                      \
   V(index_temp, ":index_temp")                                                 \
   V(is_sync, ":is_sync")                                                       \
   V(isPaused, "isPaused")                                                      \
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 66faed4..ed9e9b7 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -1030,6 +1030,7 @@
   void InitVMConstants();
 
   Random* random() { return &thread_random_; }
+  static intptr_t random_offset() { return OFFSET_OF(Thread, thread_random_); }
 
   uint64_t* GetFfiMarshalledArguments(intptr_t size) {
     if (ffi_marshalled_arguments_size_ < size) {
@@ -1138,6 +1139,7 @@
   uword exit_through_ffi_ = 0;
   ApiLocalScope* api_top_scope_;
   uint8_t double_truncate_round_supported_;
+  ALIGN8 Random thread_random_;
 
   TsanUtils* tsan_utils_ = nullptr;
 
@@ -1177,8 +1179,6 @@
 
   ErrorPtr sticky_error_;
 
-  Random thread_random_;
-
   intptr_t ffi_marshalled_arguments_size_ = 0;
   uint64_t* ffi_marshalled_arguments_;
 
diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart
index 3118350..0d1d4a8 100644
--- a/sdk/lib/_internal/vm/lib/core_patch.dart
+++ b/sdk/lib/_internal/vm/lib/core_patch.dart
@@ -53,8 +53,6 @@
 
 import "dart:isolate" show Isolate;
 
-import "dart:math" show Random;
-
 import "dart:typed_data"
     show Endian, Uint8List, Int64List, Uint16List, Uint32List;
 
diff --git a/sdk/lib/_internal/vm/lib/object_patch.dart b/sdk/lib/_internal/vm/lib/object_patch.dart
index 3a7b6bb..d0398a2 100644
--- a/sdk/lib/_internal/vm/lib/object_patch.dart
+++ b/sdk/lib/_internal/vm/lib/object_patch.dart
@@ -9,14 +9,6 @@
 @pragma("vm:external-name", "Object_getHash")
 external int _getHash(obj);
 
-/// Set hash code associated with the object if it is not set yet
-/// and return the current hash code. See [Object._objectHashCode]
-/// for why this function needs to check for already set hash code.
-@pragma("vm:recognized", "asm-intrinsic")
-@pragma("vm:exact-result-type", "dart:core#_Smi")
-@pragma("vm:external-name", "Object_setHashIfNotSetYet")
-external int _setHashIfNotSetYet(obj, int hash);
-
 @patch
 @pragma("vm:entry-point")
 class Object {
@@ -28,31 +20,9 @@
   @pragma("vm:external-name", "Object_equals")
   external bool operator ==(Object other);
 
-  // Helpers used to implement hashCode. If a hashCode is used, we remember it
-  // in a weak table in the VM (32 bit) or in the header of the object (64
-  // bit). A new hashCode value is calculated using a random number generator.
-  static final _hashCodeRnd = new Random();
-
-  static int _objectHashCode(obj) {
-    var result = _getHash(obj);
-    if (result == 0) {
-      // We want the hash to be a Smi value greater than 0.
-      do {
-        result = _hashCodeRnd.nextInt(0x40000000);
-      } while (result == 0);
-
-      // Caveat: we might be interrupted by vm-service which then
-      // can initialize [this] object's hash code, that is why we need to
-      // return the return value of [_setHashIfNotSetYet] rather than
-      // returning [result] itself.
-      return _setHashIfNotSetYet(obj, result);
-    }
-    return result;
-  }
-
   @patch
-  int get hashCode => _objectHashCode(this);
-  int get _identityHashCode => _objectHashCode(this);
+  int get hashCode => _getHash(this);
+  int get _identityHashCode => _getHash(this);
 
   @patch
   @pragma("vm:external-name", "Object_toString")