tor-browser

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

Marking-inl.h (8048B)


      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_Marking_inl_h
      8 #define gc_Marking_inl_h
      9 
     10 #include "gc/Marking.h"
     11 
     12 #include <type_traits>
     13 
     14 #include "gc/RelocationOverlay.h"
     15 #include "gc/Zone.h"
     16 #include "js/Id.h"
     17 #include "js/Value.h"
     18 #include "vm/StringType.h"
     19 #include "vm/TaggedProto.h"
     20 #include "wasm/WasmAnyRef.h"
     21 
     22 #include "gc/Nursery-inl.h"
     23 
     24 namespace js {
     25 namespace gc {
     26 
     27 // An abstraction to re-wrap any kind of typed pointer back to the tagged
     28 // pointer it came from with |TaggedPtr<TargetType>::wrap(sourcePtr)|.
     29 template <typename T>
     30 struct TaggedPtr {};
     31 
     32 template <>
     33 struct TaggedPtr<JS::Value> {
     34  static JS::Value wrap(JSObject* obj) {
     35    if (!obj) {
     36      return JS::NullValue();
     37    }
     38    return JS::ObjectValue(*obj);
     39  }
     40  static JS::Value wrap(JSString* str) { return JS::StringValue(str); }
     41  static JS::Value wrap(JS::Symbol* sym) { return JS::SymbolValue(sym); }
     42  static JS::Value wrap(JS::BigInt* bi) { return JS::BigIntValue(bi); }
     43  template <typename T>
     44  static JS::Value wrap(T* priv) {
     45    static_assert(std::is_base_of_v<Cell, T>,
     46                  "Type must be a GC thing derived from js::gc::Cell");
     47    return JS::PrivateGCThingValue(priv);
     48  }
     49  static JS::Value empty() { return JS::UndefinedValue(); }
     50 };
     51 
     52 template <>
     53 struct TaggedPtr<jsid> {
     54  static jsid wrap(JSString* str) { return JS::PropertyKey::NonIntAtom(str); }
     55  static jsid wrap(JS::Symbol* sym) { return PropertyKey::Symbol(sym); }
     56  static jsid empty() { return JS::PropertyKey::Void(); }
     57 };
     58 
     59 template <>
     60 struct TaggedPtr<TaggedProto> {
     61  static TaggedProto wrap(JSObject* obj) { return TaggedProto(obj); }
     62  static TaggedProto empty() { return TaggedProto(); }
     63 };
     64 
     65 template <>
     66 struct TaggedPtr<wasm::AnyRef> {
     67  static wasm::AnyRef wrap(JSObject* obj) {
     68    return wasm::AnyRef::fromJSObjectOrNull(obj);
     69  }
     70  static wasm::AnyRef wrap(JSString* str) {
     71    return wasm::AnyRef::fromJSString(str);
     72  }
     73  static wasm::AnyRef empty() { return wasm::AnyRef(); }
     74 };
     75 
     76 template <typename T>
     77 struct MightBeForwarded {
     78  static_assert(std::is_base_of_v<Cell, T>);
     79  static_assert(!std::is_same_v<Cell, T> && !std::is_same_v<TenuredCell, T>);
     80 
     81 #define CAN_FORWARD_KIND_OR(_1, _2, Type, _3, _4, _5, canCompact) \
     82  std::is_base_of_v<Type, T> ? canCompact:
     83 
     84  // FOR_EACH_ALLOCKIND doesn't cover every possible type: make sure
     85  // to default to `true` for unknown types.
     86  static constexpr bool value = FOR_EACH_ALLOCKIND(CAN_FORWARD_KIND_OR) true;
     87 #undef CAN_FORWARD_KIND_OR
     88 };
     89 
     90 template <typename T>
     91 inline bool IsForwarded(const T* t) {
     92  if constexpr (!MightBeForwarded<T>::value) {
     93    MOZ_ASSERT(!t->isForwarded());
     94    return false;
     95  }
     96 
     97  return t->isForwarded();
     98 }
     99 
    100 template <>
    101 inline bool IsForwarded<Cell>(const Cell* t) {
    102  return t->isForwarded();
    103 }
    104 
    105 inline bool IsForwarded(const JS::Value& value) {
    106  return value.isGCThing() && IsForwarded(value.toGCThing());
    107 }
    108 
    109 template <typename T>
    110 inline T* Forwarded(const T* t) {
    111  const RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
    112  MOZ_ASSERT(overlay->isForwarded());
    113  return reinterpret_cast<T*>(overlay->forwardingAddress());
    114 }
    115 
    116 inline JS::Value Forwarded(const JS::Value& value) {
    117  MOZ_ASSERT(IsForwarded(value));
    118  JS::Value result = value;
    119  result.changeGCThingPayload(Forwarded(value.toGCThing()));
    120  return result;
    121 }
    122 
    123 template <typename T>
    124 inline T MaybeForwarded(const T& t) {
    125  if (!IsForwarded(t)) {
    126    return t;
    127  }
    128  T result = Forwarded(t);
    129  MOZ_ASSERT(!IsForwarded(result));
    130  return result;
    131 }
    132 
    133 inline const JSClass* MaybeForwardedObjectClass(const JSObject* obj) {
    134  Shape* shape = MaybeForwarded(obj->shapeMaybeForwarded());
    135  BaseShape* baseShape = MaybeForwarded(shape->base());
    136  return baseShape->clasp();
    137 }
    138 
    139 template <typename T>
    140 inline bool MaybeForwardedObjectIs(const JSObject* obj) {
    141  MOZ_ASSERT(!obj->isForwarded());
    142  return MaybeForwardedObjectClass(obj) == &T::class_;
    143 }
    144 
    145 template <typename T>
    146 inline T& MaybeForwardedObjectAs(JSObject* obj) {
    147  MOZ_ASSERT(MaybeForwardedObjectIs<T>(obj));
    148  return *static_cast<T*>(obj);
    149 }
    150 
    151 inline RelocationOverlay::RelocationOverlay(Cell* dst) {
    152  MOZ_ASSERT(dst->flags() == 0);
    153  uintptr_t ptr = uintptr_t(dst);
    154  header_.setForwardingAddress(ptr);
    155 }
    156 
    157 /* static */
    158 inline RelocationOverlay* RelocationOverlay::forwardCell(Cell* src, Cell* dst) {
    159  MOZ_ASSERT(!src->isForwarded());
    160  MOZ_ASSERT(!dst->isForwarded());
    161  return new (src) RelocationOverlay(dst);
    162 }
    163 
    164 inline bool IsAboutToBeFinalizedDuringMinorSweep(Cell** cellp) {
    165  MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
    166 
    167  if ((*cellp)->isTenured()) {
    168    return false;
    169  }
    170 
    171  return !Nursery::getForwardedPointer(cellp);
    172 }
    173 
    174 // Special case pre-write barrier for strings used during rope flattening. This
    175 // avoids eager marking of ropes which does not immediately mark the cells if we
    176 // hit OOM. This does not traverse ropes and is instead called on every node in
    177 // a rope during flattening.
    178 inline void PreWriteBarrierDuringFlattening(JSString* str) {
    179  MOZ_ASSERT(str);
    180  MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
    181 
    182  if (IsInsideNursery(str)) {
    183    return;
    184  }
    185 
    186  auto* cell = reinterpret_cast<TenuredCell*>(str);
    187  JS::shadow::Zone* zone = cell->shadowZoneFromAnyThread();
    188  if (!zone->needsIncrementalBarrier()) {
    189    return;
    190  }
    191 
    192  MOZ_ASSERT(!str->isPermanentAndMayBeShared());
    193  MOZ_ASSERT(CurrentThreadCanAccessRuntime(zone->runtimeFromAnyThread()));
    194  PerformIncrementalBarrierDuringFlattening(str);
    195 }
    196 
    197 #ifdef JSGC_HASH_TABLE_CHECKS
    198 
    199 // Moving GC things whose pointers are used in hash table keys has the potential
    200 // to break hash tables in subtle and terrifying ways. For example, a key might
    201 // be reported as not present but iterating the table could still return it.
    202 //
    203 // Check that a table is correct following a moving GC, ensuring that nothing is
    204 // present in the table that points into the nursery or that has not been moved,
    205 // and that the hash table entries are discoverable.
    206 //
    207 // |checkEntryAndGetLookup| should check any GC thing pointers in the entry are
    208 // valid and return the lookup required to get this entry from the table.
    209 
    210 template <typename Table, typename Range, typename Lookup>
    211 void CheckTableEntryAfterMovingGC(const Table& table, const Range& r,
    212                                  const Lookup& lookup) {
    213  auto ptr = table.lookup(lookup);
    214  MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
    215 }
    216 
    217 template <typename Table, typename F>
    218 void CheckTableAfterMovingGC(const Table& table, F&& checkEntryAndGetLookup) {
    219  for (auto r = table.all(); !r.empty(); r.popFront()) {
    220    auto lookup = checkEntryAndGetLookup(r.front());
    221    CheckTableEntryAfterMovingGC(table, r, lookup);
    222  }
    223 }
    224 
    225 template <typename T>
    226 inline bool IsGCThingValidAfterMovingGC(T* t) {
    227  if (!t->isTenured()) {
    228    return false;
    229  }
    230 
    231  TenuredCell* cell = &t->asTenured();
    232  return cell->arena()->allocated() && !cell->isForwarded();
    233 }
    234 
    235 template <typename T>
    236 inline void CheckGCThingAfterMovingGC(T* t) {
    237  if (t) {
    238    MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t));
    239  }
    240 }
    241 
    242 template <typename T>
    243 inline void CheckGCThingAfterMovingGC(T* t, JS::Zone* expectedZone) {
    244  if (t) {
    245    MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t));
    246    JS::Zone* zone = t->zoneFromAnyThread();
    247    MOZ_RELEASE_ASSERT(zone == expectedZone || zone->isAtomsZone());
    248  }
    249 }
    250 
    251 template <typename T>
    252 inline void CheckGCThingAfterMovingGC(const WeakHeapPtr<T*>& t,
    253                                      JS::Zone* expectedZone) {
    254  CheckGCThingAfterMovingGC(t.unbarrieredGet(), expectedZone);
    255 }
    256 
    257 inline void CheckProtoAfterMovingGC(const TaggedProto& proto, JS::Zone* zone) {
    258  if (proto.isObject()) {
    259    CheckGCThingAfterMovingGC(proto.toObject(), zone);
    260  }
    261 }
    262 
    263 #endif  // JSGC_HASH_TABLE_CHECKS
    264 
    265 } /* namespace gc */
    266 } /* namespace js */
    267 
    268 #endif  // gc_Marking_inl_h