tor-browser

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

MapObject.h (14348B)


      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 builtin_MapObject_h
      8 #define builtin_MapObject_h
      9 
     10 #include "mozilla/MemoryReporting.h"
     11 
     12 #include "builtin/OrderedHashTableObject.h"
     13 #include "vm/JSObject.h"
     14 #include "vm/NativeObject.h"
     15 
     16 namespace js {
     17 
     18 /*
     19 * Comparing two ropes for equality can fail. The js::HashTable template
     20 * requires infallible hash() and match() operations. Therefore we require
     21 * all values to be converted to hashable form before being used as a key
     22 * in a Map or Set object.
     23 *
     24 * All values except ropes are hashable as-is.
     25 */
     26 class HashableValue {
     27  Value value;
     28 
     29 public:
     30  HashableValue() : value(UndefinedValue()) {}
     31  explicit HashableValue(JSWhyMagic whyMagic) : value(MagicValue(whyMagic)) {}
     32 
     33  [[nodiscard]] bool setValue(JSContext* cx, const Value& v);
     34  HashNumber hash(const mozilla::HashCodeScrambler& hcs) const;
     35 
     36  // Value equality. Separate BigInt instances may compare equal.
     37  bool equals(const HashableValue& other) const;
     38 
     39  // Bitwise equality.
     40  bool operator==(const HashableValue& other) const {
     41    return value == other.value;
     42  }
     43  bool operator!=(const HashableValue& other) const {
     44    return !(*this == other);
     45  }
     46 
     47  const Value& get() const { return value; }
     48  operator Value() const { return get(); }
     49 
     50  void trace(JSTracer* trc) {
     51    TraceManuallyBarrieredEdge(trc, &value, "HashableValue");
     52  }
     53 };
     54 
     55 template <typename Wrapper>
     56 class WrappedPtrOperations<HashableValue, Wrapper> {
     57 public:
     58  Value get() const { return static_cast<const Wrapper*>(this)->get().get(); }
     59 };
     60 
     61 template <typename Wrapper>
     62 class MutableWrappedPtrOperations<HashableValue, Wrapper>
     63    : public WrappedPtrOperations<HashableValue, Wrapper> {
     64 public:
     65  [[nodiscard]] bool setValue(JSContext* cx, HandleValue v) {
     66    return static_cast<Wrapper*>(this)->get().setValue(cx, v);
     67  }
     68 };
     69 
     70 template <>
     71 struct InternalBarrierMethods<HashableValue> {
     72  static bool isMarkable(const HashableValue& v) { return v.get().isGCThing(); }
     73 
     74  static void preBarrier(const HashableValue& v) {
     75    if (isMarkable(v)) {
     76      gc::ValuePreWriteBarrier(v.get());
     77    }
     78  }
     79 
     80 #ifdef DEBUG
     81  static void assertThingIsNotGray(const HashableValue& v) {
     82    JS::AssertValueIsNotGray(v.get());
     83  }
     84 #endif
     85 };
     86 
     87 struct HashableValueHasher {
     88  using Key = PreBarriered<HashableValue>;
     89  using Lookup = HashableValue;
     90 
     91  static HashNumber hash(const Lookup& v,
     92                         const mozilla::HashCodeScrambler& hcs) {
     93    return v.hash(hcs);
     94  }
     95  static bool match(const Key& k, const Lookup& l) { return k.get().equals(l); }
     96  static bool isEmpty(const Key& v) {
     97    return v.get().get().isMagic(JS_HASH_KEY_EMPTY);
     98  }
     99  static void makeEmpty(Key* vp) { vp->set(HashableValue(JS_HASH_KEY_EMPTY)); }
    100 };
    101 
    102 template <typename ObjectT>
    103 class OrderedHashTableRef;
    104 
    105 struct UnbarrieredHashPolicy;
    106 
    107 class MapObject : public OrderedHashMapObject {
    108 public:
    109  using Table = OrderedHashMapImpl<PreBarriered<HashableValue>, HeapPtr<Value>,
    110                                   HashableValueHasher>;
    111 
    112  // PreBarrieredTable has the same memory layout as Table but doesn't have
    113  // wrappers that perform post barriers on the keys/values. Used when the
    114  // MapObject is in the nursery.
    115  using PreBarrieredTable =
    116      OrderedHashMapImpl<PreBarriered<HashableValue>, PreBarriered<Value>,
    117                         HashableValueHasher>;
    118 
    119  // UnbarrieredTable has the same memory layout as Table but doesn't have any
    120  // wrappers that perform barriers on the keys/values. Used to allocate and
    121  // delete the table and when updating the nursery allocated keys map during
    122  // minor GC.
    123  using UnbarrieredTable =
    124      OrderedHashMapImpl<Value, Value, UnbarrieredHashPolicy>;
    125 
    126  friend class OrderedHashTableRef<MapObject>;
    127 
    128  enum {
    129    NurseryKeysSlot = Table::SlotCount,
    130    RegisteredNurseryIteratorsSlot,
    131    SlotCount
    132  };
    133 
    134  using IteratorKind = TableIteratorObject::Kind;
    135 
    136  static const JSClass class_;
    137  static const JSClass protoClass_;
    138 
    139  [[nodiscard]] bool getKeysAndValuesInterleaved(
    140      JS::MutableHandle<GCVector<JS::Value>> entries);
    141  [[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
    142 
    143  static MapObject* createWithProto(JSContext* cx, HandleObject proto,
    144                                    NewObjectKind newKind);
    145  static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
    146  static MapObject* createFromIterable(
    147      JSContext* cx, Handle<JSObject*> proto, Handle<Value> iterable,
    148      Handle<MapObject*> allocatedFromJit = nullptr);
    149 
    150  // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
    151  // interfaces, etc.)
    152  uint32_t size();
    153  [[nodiscard]] bool get(JSContext* cx, const Value& key,
    154                         MutableHandleValue rval);
    155  [[nodiscard]] bool has(JSContext* cx, const Value& key, bool* rval);
    156  [[nodiscard]] bool getOrInsert(JSContext* cx, const Value& key,
    157                                 const Value& val, MutableHandleValue rval);
    158  [[nodiscard]] bool delete_(JSContext* cx, const Value& key, bool* rval);
    159 
    160  // Set call for public JSAPI exposure. Does not actually return map object
    161  // as stated in spec, expects caller to return a value. for instance, with
    162  // webidl maplike/setlike, should return interface object.
    163  [[nodiscard]] bool set(JSContext* cx, const Value& key, const Value& val);
    164  void clear(JSContext* cx);
    165  [[nodiscard]] static bool iterator(JSContext* cx, IteratorKind kind,
    166                                     Handle<MapObject*> obj,
    167                                     MutableHandleValue iter);
    168 
    169  void clearNurseryIteratorsBeforeMinorGC();
    170 
    171  // Sweeps a map that had nursery memory associated with it after a minor
    172  // GC. This may finalize the map if it was in the nursery and has died.
    173  //
    174  // Returns a pointer to the map if it still has nursery memory associated with
    175  // it, or nullptr.
    176  static MapObject* sweepAfterMinorGC(JS::GCContext* gcx, MapObject* mapobj);
    177 
    178  size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf);
    179 
    180  [[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
    181  [[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
    182  [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
    183 
    184 private:
    185  static const ClassSpec classSpec_;
    186  static const JSClassOps classOps_;
    187  static const ClassExtension classExtension_;
    188 
    189  static const JSPropertySpec properties[];
    190  static const JSFunctionSpec methods[];
    191  static const JSPropertySpec staticProperties[];
    192  static const JSFunctionSpec staticMethods[];
    193 
    194  [[nodiscard]] bool setWithHashableKey(JSContext* cx, const HashableValue& key,
    195                                        const Value& value);
    196 
    197  [[nodiscard]] bool tryOptimizeCtorWithIterable(JSContext* cx,
    198                                                 const Value& iterableVal,
    199                                                 bool* optimized);
    200 
    201  static bool finishInit(JSContext* cx, HandleObject ctor, HandleObject proto);
    202 
    203  static void trace(JSTracer* trc, JSObject* obj);
    204  static size_t objectMoved(JSObject* obj, JSObject* old);
    205 
    206  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
    207 
    208  static bool is(HandleValue v);
    209  static bool is(HandleObject o);
    210 
    211  [[nodiscard]] static bool iterator_impl(JSContext* cx, const CallArgs& args,
    212                                          IteratorKind kind);
    213 
    214  [[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
    215  [[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
    216  [[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args);
    217  [[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
    218  [[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args);
    219  [[nodiscard]] static bool getOrInsert(JSContext* cx, unsigned argc,
    220                                        Value* vp);
    221  [[nodiscard]] static bool getOrInsert_impl(JSContext* cx,
    222                                             const CallArgs& args);
    223  [[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
    224  [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
    225  [[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args);
    226  [[nodiscard]] static bool keys(JSContext* cx, unsigned argc, Value* vp);
    227  [[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
    228  [[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
    229  [[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
    230  [[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
    231  [[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
    232 };
    233 
    234 class MapIteratorObject : public TableIteratorObject {
    235 public:
    236  static const JSClass class_;
    237 
    238  static const JSFunctionSpec methods[];
    239  static MapIteratorObject* create(JSContext* cx, Handle<MapObject*> mapobj,
    240                                   Kind kind);
    241  static void finalize(JS::GCContext* gcx, JSObject* obj);
    242  static size_t objectMoved(JSObject* obj, JSObject* old);
    243 
    244  [[nodiscard]] static bool next(MapIteratorObject* mapIterator,
    245                                 ArrayObject* resultPairObj);
    246 
    247  static JSObject* createResultPair(JSContext* cx);
    248 
    249 private:
    250  MapObject* target() const;
    251 };
    252 
    253 class SetObject : public OrderedHashSetObject {
    254 public:
    255  using Table =
    256      OrderedHashSetImpl<PreBarriered<HashableValue>, HashableValueHasher>;
    257  using UnbarrieredTable = OrderedHashSetImpl<Value, UnbarrieredHashPolicy>;
    258 
    259  friend class OrderedHashTableRef<SetObject>;
    260 
    261  enum {
    262    NurseryKeysSlot = Table::SlotCount,
    263    RegisteredNurseryIteratorsSlot,
    264    SlotCount
    265  };
    266 
    267  using IteratorKind = TableIteratorObject::Kind;
    268 
    269  static const JSClass class_;
    270  static const JSClass protoClass_;
    271 
    272  [[nodiscard]] bool keys(JS::MutableHandle<GCVector<JS::Value>> keys);
    273  [[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
    274  [[nodiscard]] bool add(JSContext* cx, const Value& key);
    275 
    276  // Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
    277  // interfaces, etc.)
    278  static SetObject* createWithProto(JSContext* cx, HandleObject proto,
    279                                    NewObjectKind newKind);
    280  static SetObject* create(JSContext* cx, HandleObject proto = nullptr);
    281  static SetObject* createFromIterable(
    282      JSContext* cx, Handle<JSObject*> proto, Handle<Value> iterable,
    283      Handle<SetObject*> allocatedFromJit = nullptr);
    284 
    285  uint32_t size();
    286  [[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
    287  [[nodiscard]] static bool add(JSContext* cx, unsigned argc, Value* vp);
    288  [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
    289  [[nodiscard]] bool has(JSContext* cx, const Value& key, bool* rval);
    290  void clear(JSContext* cx);
    291  [[nodiscard]] static bool iterator(JSContext* cx, IteratorKind kind,
    292                                     Handle<SetObject*> obj,
    293                                     MutableHandleValue iter);
    294  [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
    295  [[nodiscard]] bool delete_(JSContext* cx, const Value& key, bool* rval);
    296 
    297  [[nodiscard]] static bool copy(JSContext* cx, unsigned argc, Value* vp);
    298 
    299  void clearNurseryIteratorsBeforeMinorGC();
    300 
    301  // Sweeps a set that had nursery memory associated with it after a minor
    302  // GC. This may finalize the set if it was in the nursery and has died.
    303  //
    304  // Returns a pointer to the set if it still has nursery memory associated with
    305  // it, or nullptr.
    306  static SetObject* sweepAfterMinorGC(JS::GCContext* gcx, SetObject* setobj);
    307 
    308  size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf);
    309 
    310 private:
    311  static const ClassSpec classSpec_;
    312  static const JSClassOps classOps_;
    313  static const ClassExtension classExtension_;
    314 
    315  static const JSPropertySpec properties[];
    316  static const JSFunctionSpec methods[];
    317  static const JSPropertySpec staticProperties[];
    318 
    319  [[nodiscard]] bool addHashableValue(JSContext* cx,
    320                                      const HashableValue& value);
    321 
    322  [[nodiscard]] bool tryOptimizeCtorWithIterable(JSContext* cx,
    323                                                 const Value& iterableVal,
    324                                                 bool* optimized);
    325 
    326  static bool finishInit(JSContext* cx, HandleObject ctor, HandleObject proto);
    327 
    328  static void trace(JSTracer* trc, JSObject* obj);
    329  static size_t objectMoved(JSObject* obj, JSObject* old);
    330 
    331  static bool construct(JSContext* cx, unsigned argc, Value* vp);
    332 
    333  static bool is(HandleValue v);
    334  static bool is(HandleObject o);
    335 
    336  [[nodiscard]] static bool iterator_impl(JSContext* cx, const CallArgs& args,
    337                                          IteratorKind kind);
    338 
    339  [[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
    340  [[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
    341  [[nodiscard]] static bool add_impl(JSContext* cx, const CallArgs& args);
    342  [[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
    343  [[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
    344  [[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
    345  [[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
    346  [[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
    347  [[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
    348 };
    349 
    350 class SetIteratorObject : public TableIteratorObject {
    351 public:
    352  static const JSClass class_;
    353 
    354  static const JSFunctionSpec methods[];
    355  static SetIteratorObject* create(JSContext* cx, Handle<SetObject*> setobj,
    356                                   Kind kind);
    357  static void finalize(JS::GCContext* gcx, JSObject* obj);
    358  static size_t objectMoved(JSObject* obj, JSObject* old);
    359 
    360  [[nodiscard]] static bool next(SetIteratorObject* setIterator,
    361                                 ArrayObject* resultObj);
    362 
    363  static JSObject* createResult(JSContext* cx);
    364 
    365 private:
    366  SetObject* target() const;
    367 };
    368 
    369 } /* namespace js */
    370 
    371 #endif /* builtin_MapObject_h */