ShapeZone.h (8993B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_ShapeZone_h 8 #define vm_ShapeZone_h 9 10 #include "mozilla/MemoryReporting.h" 11 12 #include "gc/Barrier.h" 13 #include "js/GCHashTable.h" 14 #include "vm/PropertyKey.h" 15 #include "vm/PropMap.h" 16 #include "vm/Shape.h" 17 #include "vm/TaggedProto.h" 18 19 namespace js { 20 21 // Hash policy for the per-zone baseShapes set. 22 struct BaseShapeHasher { 23 struct Lookup { 24 const JSClass* clasp; 25 JS::Realm* realm; 26 TaggedProto proto; 27 28 Lookup(const JSClass* clasp, JS::Realm* realm, TaggedProto proto) 29 : clasp(clasp), realm(realm), proto(proto) {} 30 }; 31 32 static HashNumber hash(const Lookup& lookup) { 33 HashNumber hash = StableCellHasher<TaggedProto>::hash(lookup.proto); 34 return mozilla::AddToHash(hash, lookup.clasp, lookup.realm); 35 } 36 static bool match(const WeakHeapPtr<BaseShape*>& key, const Lookup& lookup) { 37 return key.unbarrieredGet()->clasp() == lookup.clasp && 38 key.unbarrieredGet()->realm() == lookup.realm && 39 key.unbarrieredGet()->proto() == lookup.proto; 40 } 41 }; 42 using BaseShapeSet = JS::WeakCache< 43 JS::GCHashSet<WeakHeapPtr<BaseShape*>, BaseShapeHasher, SystemAllocPolicy>>; 44 45 // Hash policy for the per-zone initialPropMaps set, mapping property key + info 46 // to a shared property map. 47 struct InitialPropMapHasher { 48 struct Lookup { 49 PropertyKey key; 50 PropertyInfo prop; 51 52 Lookup(PropertyKey key, PropertyInfo prop) : key(key), prop(prop) {} 53 }; 54 static HashNumber hash(const Lookup& lookup) { 55 HashNumber hash = HashPropertyKey(lookup.key); 56 return mozilla::AddToHash(hash, lookup.prop.toRaw()); 57 } 58 static bool match(const WeakHeapPtr<SharedPropMap*>& key, 59 const Lookup& lookup) { 60 const SharedPropMap* map = key.unbarrieredGet(); 61 return map->matchProperty(0, lookup.key, lookup.prop); 62 } 63 }; 64 using InitialPropMapSet = 65 JS::WeakCache<JS::GCHashSet<WeakHeapPtr<SharedPropMap*>, 66 InitialPropMapHasher, SystemAllocPolicy>>; 67 68 // Helper class to hash information relevant for all shapes. 69 struct ShapeBaseHasher { 70 struct Lookup { 71 const JSClass* clasp; 72 JS::Realm* realm; 73 TaggedProto proto; 74 ObjectFlags objectFlags; 75 76 Lookup(const JSClass* clasp, JS::Realm* realm, const TaggedProto& proto, 77 ObjectFlags objectFlags) 78 : clasp(clasp), realm(realm), proto(proto), objectFlags(objectFlags) {} 79 }; 80 81 static HashNumber hash(const Lookup& lookup) { 82 HashNumber hash = StableCellHasher<TaggedProto>::hash(lookup.proto); 83 return mozilla::AddToHash(hash, lookup.clasp, lookup.realm, 84 lookup.objectFlags.toRaw()); 85 } 86 static bool match(const Shape* shape, const Lookup& lookup) { 87 return lookup.clasp == shape->getObjectClass() && 88 lookup.realm == shape->realm() && lookup.proto == shape->proto() && 89 lookup.objectFlags == shape->objectFlags(); 90 } 91 }; 92 93 // Hash policy for the per-zone initialShapes set storing initial shapes for 94 // objects in the zone. 95 // 96 // These are empty shapes, except for certain classes (e.g. String, RegExp) 97 // which may add certain baked-in properties. See insertInitialShape. 98 struct InitialShapeHasher { 99 struct Lookup : public ShapeBaseHasher::Lookup { 100 uint32_t nfixed; 101 102 Lookup(const JSClass* clasp, JS::Realm* realm, const TaggedProto& proto, 103 uint32_t nfixed, ObjectFlags objectFlags) 104 : ShapeBaseHasher::Lookup(clasp, realm, proto, objectFlags), 105 nfixed(nfixed) {} 106 }; 107 108 static HashNumber hash(const Lookup& lookup) { 109 HashNumber hash = ShapeBaseHasher::hash(lookup); 110 return mozilla::AddToHash(hash, lookup.nfixed); 111 } 112 static bool match(const WeakHeapPtr<SharedShape*>& key, 113 const Lookup& lookup) { 114 const SharedShape* shape = key.unbarrieredGet(); 115 return ShapeBaseHasher::match(shape, lookup) && 116 lookup.nfixed == shape->numFixedSlots(); 117 } 118 }; 119 using InitialShapeSet = 120 JS::WeakCache<JS::GCHashSet<WeakHeapPtr<SharedShape*>, InitialShapeHasher, 121 SystemAllocPolicy>>; 122 123 // Hash policy for the per-zone propMapShapes set storing shared shapes with 124 // shared property maps. 125 struct PropMapShapeHasher { 126 struct Lookup { 127 BaseShape* base; 128 SharedPropMap* map; 129 uint32_t mapLength; 130 uint32_t nfixed; 131 ObjectFlags objectFlags; 132 133 Lookup(BaseShape* base, uint32_t nfixed, SharedPropMap* map, 134 uint32_t mapLength, ObjectFlags objectFlags) 135 : base(base), 136 map(map), 137 mapLength(mapLength), 138 nfixed(nfixed), 139 objectFlags(objectFlags) {} 140 }; 141 142 static HashNumber hash(const Lookup& lookup) { 143 return mozilla::HashGeneric(lookup.base, lookup.map, lookup.mapLength, 144 lookup.nfixed, lookup.objectFlags.toRaw()); 145 } 146 static bool match(const WeakHeapPtr<SharedShape*>& key, 147 const Lookup& lookup) { 148 const SharedShape* shape = key.unbarrieredGet(); 149 return lookup.base == shape->base() && 150 lookup.nfixed == shape->numFixedSlots() && 151 lookup.map == shape->propMap() && 152 lookup.mapLength == shape->propMapLength() && 153 lookup.objectFlags == shape->objectFlags(); 154 } 155 static void rekey(WeakHeapPtr<SharedShape*>& k, 156 const WeakHeapPtr<SharedShape*>& newKey) { 157 k = newKey; 158 } 159 }; 160 using PropMapShapeSet = 161 JS::WeakCache<JS::GCHashSet<WeakHeapPtr<SharedShape*>, PropMapShapeHasher, 162 SystemAllocPolicy>>; 163 164 // Hash policy for the per-zone proxyShapes set storing shapes for proxy objects 165 // in the zone. 166 struct ProxyShapeHasher : public ShapeBaseHasher { 167 static bool match(const WeakHeapPtr<ProxyShape*>& key, const Lookup& lookup) { 168 const ProxyShape* shape = key.unbarrieredGet(); 169 return ShapeBaseHasher::match(shape, lookup); 170 } 171 }; 172 using ProxyShapeSet = 173 JS::WeakCache<JS::GCHashSet<WeakHeapPtr<ProxyShape*>, ProxyShapeHasher, 174 SystemAllocPolicy>>; 175 176 // Hash policy for the per-zone wasmGCShapes set storing shapes for Wasm GC 177 // objects in the zone. 178 struct WasmGCShapeHasher : public ShapeBaseHasher { 179 struct Lookup : public ShapeBaseHasher::Lookup { 180 const wasm::RecGroup* recGroup; 181 182 Lookup(const JSClass* clasp, JS::Realm* realm, const TaggedProto& proto, 183 const wasm::RecGroup* recGroup, ObjectFlags objectFlags) 184 : ShapeBaseHasher::Lookup(clasp, realm, proto, objectFlags), 185 recGroup(recGroup) {} 186 }; 187 188 static HashNumber hash(const Lookup& lookup) { 189 HashNumber hash = ShapeBaseHasher::hash(lookup); 190 hash = mozilla::AddToHash(hash, lookup.recGroup); 191 return hash; 192 } 193 194 static bool match(const WeakHeapPtr<WasmGCShape*>& key, 195 const Lookup& lookup) { 196 const WasmGCShape* shape = key.unbarrieredGet(); 197 return ShapeBaseHasher::match(shape, lookup) && 198 shape->recGroup() == lookup.recGroup; 199 } 200 }; 201 using WasmGCShapeSet = 202 JS::WeakCache<JS::GCHashSet<WeakHeapPtr<WasmGCShape*>, WasmGCShapeHasher, 203 SystemAllocPolicy>>; 204 205 struct ShapeZone { 206 // Set of all base shapes in the Zone. 207 BaseShapeSet baseShapes; 208 209 // Set used to look up a shared property map based on the first property's 210 // PropertyKey and PropertyInfo. 211 InitialPropMapSet initialPropMaps; 212 213 // Set of initial shapes in the Zone. 214 InitialShapeSet initialShapes; 215 216 // Set of SharedPropMapShapes in the Zone. 217 PropMapShapeSet propMapShapes; 218 219 // Set of ProxyShapes in the Zone. 220 ProxyShapeSet proxyShapes; 221 222 // Set of WasmGCShapes in the Zone. 223 WasmGCShapeSet wasmGCShapes; 224 225 using ShapeWithCacheVector = js::Vector<js::Shape*, 0, js::SystemAllocPolicy>; 226 ShapeWithCacheVector shapesWithCache; 227 228 explicit ShapeZone(Zone* zone); 229 230 void purgeShapeCaches(JS::GCContext* gcx); 231 232 void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, 233 size_t* initialPropMapTable, size_t* shapeTables); 234 235 void fixupPropMapShapeTableAfterMovingGC(); 236 237 #ifdef JSGC_HASH_TABLE_CHECKS 238 void checkTablesAfterMovingGC(JS::Zone* zone); 239 #endif 240 241 // Return true if we should use dictionary mode teleportation. 242 // This counts reshape requests and will start returning false 243 // after a number (RESHAPE_MAX) of queries. 244 bool useDictionaryModeTeleportation(); 245 246 private: 247 // The number of teleporting reshapes which have occurred for this 248 // shape zone. Used to avoid pathological cases of continuous reshape 249 uint16_t reshapeCounter{}; 250 251 // The limit of reshapes allowed. After this teleporting is disabled 252 // rather than continue doing reshapes. 253 static const uint16_t RESHAPE_MAX = 5000; 254 }; 255 256 } // namespace js 257 258 #endif /* vm_ShapeZone_h */