tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */