From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pedro Pontes <pepontes@microsoft.com>
Date: Thu, 29 Jun 2023 01:16:50 -0700
Subject: Fix using shared objects as prototypes more (Partial backport)

The previous fix from
https://chromium-review.googlesource.com/c/v8/v8/+/4086127 was
insufficient. It prevented shared objects from being optimized as
prototypes, but callers of OptimizeAsPrototype also assume that all
JSObjects can track prototype users via prototype_info on the map.

This CL attempts a broader fix where shared objects are not considered
optimizable as prototypes at all. When used as a prototype, shared
objects are treated like non-JSObjects (e.g. JSProxy, WasmObject).

Bug: chromium:1401295, v8:12547
Change-Id: I9886e9ccac9e597e7dd34a09083a096ff4e3bf16
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4112150
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84916}

diff --git a/src/objects/heap-object.h b/src/objects/heap-object.h
index 806b34b969eeaccc7f16cfd0ac734d667b165943..b2d401ba823231f939b8d1ae4f44660360276053 100644
--- a/src/objects/heap-object.h
+++ b/src/objects/heap-object.h
@@ -113,6 +113,8 @@ class HeapObject : public Object {
   STRUCT_LIST(DECL_STRUCT_PREDICATE)
 #undef DECL_STRUCT_PREDICATE
 
+  V8_INLINE bool IsJSObjectThatCanBeTrackedAsPrototype() const;
+
   // Converts an address to a HeapObject pointer.
   static inline HeapObject FromAddress(Address address) {
     DCHECK_TAG_ALIGNED(address);
diff --git a/src/objects/objects-inl.h b/src/objects/objects-inl.h
index 025c87dbf313cc4b3adb884b4b2d96940c4ce389..baa1167a123b4c161d06b9869938d3cbd4f15fb2 100644
--- a/src/objects/objects-inl.h
+++ b/src/objects/objects-inl.h
@@ -83,6 +83,11 @@ bool Object::InSharedWritableHeap() const {
   return IsHeapObject() && HeapObject::cast(*this).InSharedWritableHeap();
 }
 
+bool Object::IsJSObjectThatCanBeTrackedAsPrototype() const {
+  return IsHeapObject() &&
+         HeapObject::cast(*this).IsJSObjectThatCanBeTrackedAsPrototype();
+}
+
 #define IS_TYPE_FUNCTION_DEF(type_)                                        \
   bool Object::Is##type_() const {                                         \
     return IsHeapObject() && HeapObject::cast(*this).Is##type_();          \
@@ -189,6 +194,13 @@ bool HeapObject::InSharedWritableHeap() const {
   return BasicMemoryChunk::FromHeapObject(*this)->InSharedHeap();
 }
 
+bool HeapObject::IsJSObjectThatCanBeTrackedAsPrototype() const {
+  // Do not optimize objects in the shared heap because it is not
+  // threadsafe. Objects in the shared heap have fixed layouts and their maps
+  // never change.
+  return IsJSObject() && !InSharedWritableHeap();
+}
+
 bool HeapObject::IsNullOrUndefined(Isolate* isolate) const {
   return IsNullOrUndefined(ReadOnlyRoots(isolate));
 }
diff --git a/src/objects/objects.h b/src/objects/objects.h
index c3a0cbf15a329d0e4e68aa5fd379352a1cc061ba..8814ddadc4bfaac6e243a94c4890147b6ea5b4b9 100644
--- a/src/objects/objects.h
+++ b/src/objects/objects.h
@@ -341,6 +341,8 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> {
   bool IsWasmObject(Isolate* = nullptr) const { return false; }
 #endif
 
+  V8_INLINE bool IsJSObjectThatCanBeTrackedAsPrototype() const;
+
   enum class Conversion { kToNumber, kToNumeric };
 
 #define DECL_STRUCT_PREDICATE(NAME, Name, name) \
