tor-browser

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

StableCellHasher-inl.h (6793B)


      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 gc_StableCellHasher_inl_h
      8 #define gc_StableCellHasher_inl_h
      9 
     10 #include "gc/StableCellHasher.h"
     11 
     12 #include "mozilla/HashFunctions.h"
     13 
     14 #include "gc/Cell.h"
     15 #include "gc/Marking.h"
     16 #include "gc/Zone.h"
     17 #include "vm/JSObject.h"
     18 #include "vm/NativeObject.h"
     19 #include "vm/Runtime.h"
     20 
     21 namespace js {
     22 namespace gc {
     23 
     24 extern uint64_t NextCellUniqueId(JSRuntime* rt);
     25 
     26 inline bool MaybeGetUniqueId(Cell* cell, uint64_t* uidp) {
     27  MOZ_ASSERT(uidp);
     28  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()) ||
     29             CurrentThreadIsPerformingGC());
     30 
     31  if (cell->is<JSObject>()) {
     32    JSObject* obj = cell->as<JSObject>();
     33    if (obj->is<NativeObject>()) {
     34      auto* nobj = &obj->as<NativeObject>();
     35      if (!nobj->hasUniqueId()) {
     36        return false;
     37      }
     38 
     39      *uidp = nobj->uniqueId();
     40      return true;
     41    }
     42  }
     43 
     44  // Get an existing uid, if one has been set.
     45  auto p = cell->zone()->uniqueIds().readonlyThreadsafeLookup(cell);
     46  if (!p) {
     47    return false;
     48  }
     49 
     50  *uidp = p->value();
     51 
     52  return true;
     53 }
     54 
     55 extern bool CreateUniqueIdForNativeObject(NativeObject* obj, uint64_t* uidp);
     56 extern bool CreateUniqueIdForNonNativeObject(Cell* cell, UniqueIdMap::AddPtr,
     57                                             uint64_t* uidp);
     58 
     59 inline bool GetOrCreateUniqueId(Cell* cell, uint64_t* uidp) {
     60  MOZ_ASSERT(uidp);
     61  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()) ||
     62             CurrentThreadIsPerformingGC());
     63 
     64  if (cell->is<JSObject>()) {
     65    JSObject* obj = cell->as<JSObject>();
     66    if (obj->is<NativeObject>()) {
     67      auto* nobj = &obj->as<NativeObject>();
     68      if (nobj->hasUniqueId()) {
     69        *uidp = nobj->uniqueId();
     70        return true;
     71      }
     72 
     73      return CreateUniqueIdForNativeObject(nobj, uidp);
     74    }
     75  }
     76 
     77  // Get an existing uid, if one has been set.
     78  auto p = cell->zone()->uniqueIds().lookupForAdd(cell);
     79  if (p) {
     80    *uidp = p->value();
     81    return true;
     82  }
     83 
     84  return CreateUniqueIdForNonNativeObject(cell, p, uidp);
     85 }
     86 
     87 inline bool SetOrUpdateUniqueId(JSContext* cx, Cell* cell, uint64_t uid) {
     88  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()));
     89 
     90  if (cell->is<JSObject>()) {
     91    JSObject* obj = cell->as<JSObject>();
     92    if (obj->is<NativeObject>()) {
     93      auto* nobj = &obj->as<NativeObject>();
     94      return nobj->setOrUpdateUniqueId(cx, uid);
     95    }
     96  }
     97 
     98  // If the cell was in the nursery, hopefully unlikely, then we need to
     99  // tell the nursery about it so that it can sweep the uid if the thing
    100  // does not get tenured.
    101  JSRuntime* runtime = cell->runtimeFromMainThread();
    102  if (IsInsideNursery(cell) &&
    103      !runtime->gc.nursery().addedUniqueIdToCell(cell)) {
    104    return false;
    105  }
    106 
    107  return cell->zone()->uniqueIds().put(cell, uid);
    108 }
    109 
    110 inline uint64_t GetUniqueIdInfallible(Cell* cell) {
    111  uint64_t uid;
    112  AutoEnterOOMUnsafeRegion oomUnsafe;
    113  if (!GetOrCreateUniqueId(cell, &uid)) {
    114    oomUnsafe.crash("failed to allocate uid");
    115  }
    116  return uid;
    117 }
    118 
    119 inline bool HasUniqueId(Cell* cell) {
    120  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()) ||
    121             CurrentThreadIsPerformingGC());
    122 
    123  if (cell->is<JSObject>()) {
    124    JSObject* obj = cell->as<JSObject>();
    125    if (obj->is<NativeObject>()) {
    126      return obj->as<NativeObject>().hasUniqueId();
    127    }
    128  }
    129 
    130  return cell->zone()->uniqueIds().has(cell);
    131 }
    132 
    133 inline void TransferUniqueId(Cell* tgt, Cell* src) {
    134  MOZ_ASSERT(src != tgt);
    135  MOZ_ASSERT(CurrentThreadCanAccessRuntime(tgt->runtimeFromAnyThread()));
    136  MOZ_ASSERT(src->zone() == tgt->zone());
    137 
    138  Zone* zone = tgt->zone();
    139  MOZ_ASSERT_IF(zone->uniqueIds().has(src), !zone->uniqueIds().has(tgt));
    140  zone->uniqueIds().rekeyIfMoved(src, tgt);
    141 }
    142 
    143 inline void RemoveUniqueId(Cell* cell) {
    144  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()));
    145  // The cell may no longer be in the hash table if it was swapped with a
    146  // NativeObject.
    147  cell->zone()->uniqueIds().remove(cell);
    148 }
    149 
    150 }  // namespace gc
    151 
    152 static inline js::HashNumber UniqueIdToHash(uint64_t uid) {
    153  // This uses the default hasher which returns the lower 32 bits of 64 bit
    154  // integers as the hash code. This is OK because he result will be scrambled
    155  // later by ScrambleHashCode().
    156  return DefaultHasher<uint64_t>::hash(uid);
    157 }
    158 
    159 template <typename T>
    160 /* static */ bool StableCellHasher<T>::maybeGetHash(const Lookup& l,
    161                                                    HashNumber* hashOut) {
    162  if (!l) {
    163    *hashOut = 0;
    164    return true;
    165  }
    166 
    167  uint64_t uid;
    168  if (!gc::MaybeGetUniqueId(l, &uid)) {
    169    return false;
    170  }
    171 
    172  *hashOut = UniqueIdToHash(uid);
    173  return true;
    174 }
    175 
    176 template <typename T>
    177 /* static */ bool StableCellHasher<T>::ensureHash(const Lookup& l,
    178                                                  HashNumber* hashOut) {
    179  if (!l) {
    180    *hashOut = 0;
    181    return true;
    182  }
    183 
    184  uint64_t uid;
    185  if (!gc::GetOrCreateUniqueId(l, &uid)) {
    186    return false;
    187  }
    188 
    189  *hashOut = UniqueIdToHash(uid);
    190  return true;
    191 }
    192 
    193 template <typename T>
    194 /* static */ HashNumber StableCellHasher<T>::hash(const Lookup& l) {
    195  if (!l) {
    196    return 0;
    197  }
    198 
    199  // We have to access the zone from-any-thread here: a worker thread may be
    200  // cloning a self-hosted object from the main runtime's self- hosting zone
    201  // into another runtime. The zone's uid lock will protect against multiple
    202  // workers doing this simultaneously.
    203  MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
    204             CurrentThreadIsPerformingGC());
    205 
    206  return UniqueIdToHash(gc::GetUniqueIdInfallible(l));
    207 }
    208 
    209 template <typename T>
    210 /* static */ bool StableCellHasher<T>::match(const Key& k, const Lookup& l) {
    211  if (k == l) {
    212    return true;
    213  }
    214 
    215  if (!k || !l) {
    216    return false;
    217  }
    218 
    219  MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
    220             CurrentThreadIsPerformingGC());
    221 
    222 #ifdef DEBUG
    223  // Incremental table sweeping means that existing table entries may no
    224  // longer have unique IDs. We fail the match in that case and the entry is
    225  // removed from the table later on.
    226  if (!gc::HasUniqueId(k)) {
    227    Key key = k;
    228    MOZ_ASSERT(key->zoneFromAnyThread()->needsIncrementalBarrier() &&
    229               !key->isMarkedAny());
    230  }
    231  MOZ_ASSERT(gc::HasUniqueId(l));
    232 #endif
    233 
    234  uint64_t keyId;
    235  if (!gc::MaybeGetUniqueId(k, &keyId)) {
    236    // Key is dead and cannot match lookup which must be live.
    237    return false;
    238  }
    239 
    240  return keyId == gc::GetUniqueIdInfallible(l);
    241 }
    242 
    243 }  // namespace js
    244 
    245 #endif  // gc_StableCellHasher_inl_h