tor-browser

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

TaggedProto.h (5214B)


      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_TaggedProto_h
      8 #define vm_TaggedProto_h
      9 
     10 #include "mozilla/Maybe.h"
     11 
     12 #include "gc/Barrier.h"
     13 #include "js/HashTable.h"
     14 #include "js/RootingAPI.h"
     15 
     16 class JSObject;
     17 
     18 namespace js {
     19 
     20 // Information about an object prototype, which can be either a particular
     21 // object, null, or a lazily generated object. The latter is only used by
     22 // certain kinds of proxies.
     23 class TaggedProto {
     24 public:
     25  static JSObject* const LazyProto;
     26 
     27  TaggedProto() : proto(nullptr) {}
     28  TaggedProto(const TaggedProto& other) = default;
     29  explicit TaggedProto(JSObject* proto) : proto(proto) {}
     30 
     31  bool isDynamic() const { return proto == LazyProto; }
     32  bool isObject() const {
     33    /* Skip nullptr and LazyProto. */
     34    return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
     35  }
     36  JSObject* toObject() const {
     37    MOZ_ASSERT(isObject());
     38    return proto;
     39  }
     40  JSObject* toObjectOrNull() const {
     41    MOZ_ASSERT(!proto || isObject());
     42    return proto;
     43  }
     44  JSObject* raw() const { return proto; }
     45 
     46  bool operator==(const TaggedProto& other) const {
     47    return proto == other.proto;
     48  }
     49  bool operator!=(const TaggedProto& other) const {
     50    return proto != other.proto;
     51  }
     52 
     53  HashNumber hashCode() const;
     54 
     55  void trace(JSTracer* trc);
     56 
     57 private:
     58  JSObject* proto;
     59 };
     60 
     61 template <>
     62 struct StableCellHasher<TaggedProto> {
     63  using Key = TaggedProto;
     64  using Lookup = TaggedProto;
     65 
     66  static bool maybeGetHash(const Lookup& l, HashNumber* hashOut) {
     67    if (!l.isObject()) {
     68      *hashOut = hash(l);
     69      return true;
     70    }
     71 
     72    return StableCellHasher<JSObject*>::maybeGetHash(l.toObject(), hashOut);
     73  }
     74  static bool ensureHash(const Lookup& l, HashNumber* hashOut) {
     75    if (!l.isObject()) {
     76      *hashOut = hash(l);
     77      return true;
     78    }
     79    return StableCellHasher<JSObject*>::ensureHash(l.toObject(), hashOut);
     80  }
     81  static HashNumber hash(const Lookup& l) {
     82    if (l.isDynamic()) {
     83      return uint64_t(1);
     84    }
     85    if (!l.isObject()) {
     86      return uint64_t(0);
     87    }
     88    return StableCellHasher<JSObject*>::hash(l.toObject());
     89  }
     90  static bool match(const Key& k, const Lookup& l) {
     91    return k.isDynamic() == l.isDynamic() && k.isObject() == l.isObject() &&
     92           (!k.isObject() ||
     93            StableCellHasher<JSObject*>::match(k.toObject(), l.toObject()));
     94  }
     95 };
     96 
     97 #ifdef DEBUG
     98 MOZ_ALWAYS_INLINE void AssertTaggedProtoIsNotGray(const TaggedProto& proto) {
     99  if (proto.isObject()) {
    100    JS::AssertObjectIsNotGray(proto.toObject());
    101  }
    102 }
    103 #endif
    104 
    105 template <>
    106 struct InternalBarrierMethods<TaggedProto> {
    107  static void preBarrier(TaggedProto& proto);
    108 
    109  static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
    110 
    111  static void readBarrier(const TaggedProto& proto);
    112 
    113  static bool isMarkable(const TaggedProto& proto) { return proto.isObject(); }
    114 
    115 #ifdef DEBUG
    116  static void assertThingIsNotGray(const TaggedProto& proto) {
    117    AssertTaggedProtoIsNotGray(proto);
    118  }
    119 #endif
    120 };
    121 
    122 template <class Wrapper>
    123 class WrappedPtrOperations<TaggedProto, Wrapper> {
    124  const TaggedProto& value() const {
    125    return static_cast<const Wrapper*>(this)->get();
    126  }
    127 
    128 public:
    129  uintptr_t toWord() const { return value().toWord(); }
    130  inline bool isDynamic() const { return value().isDynamic(); }
    131  inline bool isObject() const { return value().isObject(); }
    132  inline JSObject* toObject() const { return value().toObject(); }
    133  inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
    134  JSObject* raw() const { return value().raw(); }
    135  HashNumber hashCode() const { return value().hashCode(); }
    136  uint64_t uniqueId() const { return value().uniqueId(); }
    137 };
    138 
    139 // If the TaggedProto is a JSObject pointer, convert to that type and call |f|
    140 // with the pointer. If the TaggedProto is lazy, returns None().
    141 template <typename F>
    142 auto MapGCThingTyped(const TaggedProto& proto, F&& f) {
    143  if (proto.isObject()) {
    144    return mozilla::Some(f(proto.toObject()));
    145  }
    146  using ReturnType = decltype(f(static_cast<JSObject*>(nullptr)));
    147  return mozilla::Maybe<ReturnType>();
    148 }
    149 
    150 template <typename F>
    151 bool ApplyGCThingTyped(const TaggedProto& proto, F&& f) {
    152  return MapGCThingTyped(proto,
    153                         [&f](auto t) {
    154                           f(t);
    155                           return true;
    156                         })
    157      .isSome();
    158 }
    159 
    160 // Since JSObject pointers are either nullptr or a valid object and since the
    161 // object layout of TaggedProto is identical to a bare object pointer, we can
    162 // safely treat a pointer to an already-rooted object (e.g. HandleObject) as a
    163 // pointer to a TaggedProto.
    164 inline Handle<TaggedProto> AsTaggedProto(HandleObject obj) {
    165  static_assert(sizeof(JSObject*) == sizeof(TaggedProto),
    166                "TaggedProto must be binary compatible with JSObject");
    167  return Handle<TaggedProto>::fromMarkedLocation(
    168      reinterpret_cast<TaggedProto const*>(obj.address()));
    169 }
    170 
    171 }  // namespace js
    172 
    173 #endif  // vm_TaggedProto_h