diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
index 9d0e729beb7fe6c4440164e01a511b796ad65753..94e75221e679af91788ca82971173f1eaaf0a337 100644
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -32,51 +32,85 @@
 //
 // A Shape represents the layout of an object. It stores and implies:
 //
-//  * The object's JSClass, Realm, prototype (see BaseShape).
-//  * For native objects, the object's properties (PropMap and map length).
-//  * The fixed slot capacity of the object (numFixedSlots).
+//  * The object's JSClass, Realm, prototype (see BaseShape section below).
 //  * The object's flags (ObjectFlags).
+//  * For native objects, the object's properties (PropMap and map length).
+//  * For native objects, the fixed slot capacity of the object (numFixedSlots).
 //
-// The shape implies the property structure (keys, attributes, property order
-// for enumeration) but not the property values. The values are stored in object
-// slots.
+// For native objects, the shape implies the property structure (keys,
+// attributes, property order for enumeration) but not the property values.
+// The values are stored in object slots.
 //
 // Every JSObject has a pointer, |shape_|, accessible via shape(), to the
 // current shape of the object. This pointer permits fast object layout tests.
 //
-// There are two kinds of shapes:
+// Shapes use the following C++ class hierarchy:
+//
+// C++ Type                     Used by
+// ============================ ====================================
+// Shape (abstract)             JSObject
+//  |
+//  +-- NativeShape (abstract)  NativeObject
+//  |    |
+//  |    +-- SharedShape        NativeObject with a shared shape
+//  |    |
+//  |    +-- DictionaryShape    NativeObject with a dictionary shape
+//  |
+//  +-- ProxyShape              ProxyObject
+//  |
+//  +-- WasmGCShape             WasmGCObject
+//
+// Classes marked with (abstract) above are not literally C++ Abstract Base
+// Classes (since there are no virtual functions, pure or not, in this
+// hierarchy), but have the same meaning: there are no shapes with this type as
+// its most-derived type.
+//
+// SharedShape
+// ===========
+// Used only for native objects. This is either an initial shape (no property
+// map) or SharedPropMap shape (for objects with at least one property).
+//
+// These are immutable tuples stored in a hash table, so that objects with the
+// same structure end up with the same shape (this both saves memory and allows
+// JIT optimizations based on this shape).
 //
-// * Shared shapes. Either initial shapes (no property map) or SharedPropMap
-//   shapes (for native objects with properties).
+// To avoid hash table lookups on the hot addProperty path, shapes have a
+// ShapeCachePtr that's used as cache for this. This cache is purged on GC.
+// The shape cache is also used as cache for prototype shapes, to point to the
+// initial shape for objects using that shape, and for cached iterators.
 //
-//   These are immutable tuples stored in a hash table, so that objects with the
-//   same structure end up with the same shape (this both saves memory and
-//   allows JIT optimizations based on this shape).
+// DictionaryShape
+// ===============
+// Used only for native objects. An object with a dictionary shape is "in
+// dictionary mode". Certain property operations are not supported for shared
+// maps so in these cases we need to convert the object to dictionary mode by
+// creating a dictionary property map and a dictionary shape. An object is
+// converted to dictionary mode in the following cases:
 //
-//   To avoid hash table lookups on the hot addProperty path, shapes have a
-//   ShapeCachePtr that's used as cache for this. This cache is purged on GC.
-//   The shape cache is also used as cache for prototype shapes, to point to the
-//   initial shape for objects using that shape, and for cached iterators.
+// - Changing a property's flags/attributes and the property is not the last
+//   property.
+// - Removing a property other than the object's last property.
+// - The object has many properties. See maybeConvertToDictionaryForAdd for the
+//   heuristics.
 //
-// * Dictionary shapes. Used only for native objects. An object with a
-//   dictionary shape is "in dictionary mode". Certain property operations
-//   are not supported for shared maps so in these cases we need to convert the
-//   object to dictionary mode by creating a dictionary property map and a
-//   dictionary shape. An object is converted to dictionary mode in the
-//   following cases:
+// Dictionary shapes are unshared, private to a single object, and always have a
+// a DictionaryPropMap that's similarly unshared. Dictionary shape mutations do
+// require allocating a new dictionary shape for the object, to properly
+// invalidate JIT inline caches and other shape guards.
+// See NativeObject::generateNewDictionaryShape.
 //
-//   - Changing a property's flags/attributes and the property is not the last
-//     property.
-//   - Removing a property other than the object's last property.
-//   - The object has many properties. See maybeConvertToDictionaryForAdd for
-//     the heuristics.
+// ProxyShape
+// ==========
+// Shape used for proxy objects (including wrappers). Proxies with the same
+// JSClass, Realm, prototype and ObjectFlags will have the same shape.
 //
-//   Dictionary shapes are unshared, private to a single object, and always have
-//   a DictionaryPropMap that's similarly unshared. Dictionary shape mutations
-//   do require allocating a new dictionary shape for the object, to properly
-//   invalidate JIT inline caches and other shape guards.
-//   See NativeObject::generateNewDictionaryShape.
+// WasmGCShape
+// ===========
+// Shape used for Wasm GC objects. Wasm GC objects with the same JSClass, Realm,
+// prototype and ObjectFlags will have the same shape.
 //
+// BaseShape
+// =========
 // Because many Shapes have similar data, there is actually a secondary type
 // called a BaseShape that holds some of a Shape's data (the JSClass, Realm,
 // prototype). Many shapes can share a single BaseShape.
@@ -282,9 +316,9 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
   // compilation can access the immutableFlags word, so we don't want any
   // mutable state here to avoid (TSan) races.
   enum ImmutableFlags : uint32_t {
-    // The length associated with the property map. This is a value in the range
-    // [0, PropMap::Capacity]. A length of 0 indicates the object is empty (has
-    // no properties).
+    // For NativeShape: the length associated with the property map. This is a
+    // value in the range [0, PropMap::Capacity]. A length of 0 indicates the
+    // object is empty (has no properties).
     MAP_LENGTH_MASK = BitMask(4),
 
     // The Shape Kind. The NativeObject kinds have the low bit set.
@@ -292,14 +326,14 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
     KIND_MASK = 0b11,
     IS_NATIVE_BIT = 0x1 << KIND_SHIFT,
 
-    // Number of fixed slots in objects with this shape.
+    // For NativeShape: the number of fixed slots in objects with this shape.
     // FIXED_SLOTS_MAX is the biggest count of fixed slots a Shape can store.
     FIXED_SLOTS_MAX = 0x1f,
     FIXED_SLOTS_SHIFT = 6,
     FIXED_SLOTS_MASK = uint32_t(FIXED_SLOTS_MAX << FIXED_SLOTS_SHIFT),
 
-    // For non-dictionary shapes: the slot span of the object, if it fits in a
-    // single byte. If the value is SMALL_SLOTSPAN_MAX, the slot span has to be
+    // For SharedShape: the slot span of the object, if it fits in a single
+    // byte. If the value is SMALL_SLOTSPAN_MAX, the slot span has to be
     // computed based on the property map (which is slower).
     //
     // Note: NativeObject::addProperty will convert to dictionary mode before we
@@ -313,9 +347,9 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
   uint32_t immutableFlags;   // Immutable flags, see above.
   ObjectFlags objectFlags_;  // Immutable object flags, see ObjectFlags.
 
-  // The shape's property map. This is either nullptr for shared initial (empty)
-  // shapes, a SharedPropMap for SharedPropMap shapes, or a DictionaryPropMap
-  // for dictionary shapes.
+  // For NativeShape: the shape's property map. This is either nullptr (for an
+  // initial SharedShape with no properties), a SharedPropMap (for SharedShape)
+  // or a DictionaryPropMap (for DictionaryShape).
   GCPtr<PropMap*> nativePropMap_;
 
   // Cache used to speed up common operations on shapes.