LCOV - code coverage report
Current view: top level - js/src/builtin - MapObject.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 425 739 57.5 %
Date: 2017-07-14 16:53:18 Functions: 82 133 61.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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             : #include "builtin/MapObject.h"
       8             : 
       9             : #include "jscntxt.h"
      10             : #include "jsiter.h"
      11             : #include "jsobj.h"
      12             : 
      13             : #include "ds/OrderedHashTable.h"
      14             : #include "gc/Marking.h"
      15             : #include "js/Utility.h"
      16             : #include "vm/GlobalObject.h"
      17             : #include "vm/Interpreter.h"
      18             : #include "vm/SelfHosting.h"
      19             : #include "vm/Symbol.h"
      20             : 
      21             : #include "jsobjinlines.h"
      22             : 
      23             : #include "vm/Interpreter-inl.h"
      24             : #include "vm/NativeObject-inl.h"
      25             : 
      26             : using namespace js;
      27             : 
      28             : using mozilla::ArrayLength;
      29             : using mozilla::IsNaN;
      30             : using mozilla::NumberEqualsInt32;
      31             : 
      32             : using JS::DoubleNaNValue;
      33             : using JS::ForOfIterator;
      34             : 
      35             : 
      36             : /*** HashableValue *******************************************************************************/
      37             : 
      38             : bool
      39        2327 : HashableValue::setValue(JSContext* cx, HandleValue v)
      40             : {
      41        2327 :     if (v.isString()) {
      42             :         // Atomize so that hash() and operator==() are fast and infallible.
      43        2015 :         JSString* str = AtomizeString(cx, v.toString(), DoNotPinAtom);
      44        2015 :         if (!str)
      45           0 :             return false;
      46        2015 :         value = StringValue(str);
      47         312 :     } else if (v.isDouble()) {
      48           2 :         double d = v.toDouble();
      49             :         int32_t i;
      50           2 :         if (NumberEqualsInt32(d, &i)) {
      51             :             // Normalize int32_t-valued doubles to int32_t for faster hashing and testing.
      52           0 :             value = Int32Value(i);
      53           2 :         } else if (IsNaN(d)) {
      54             :             // NaNs with different bits must hash and test identically.
      55           0 :             value = DoubleNaNValue();
      56             :         } else {
      57           2 :             value = v;
      58             :         }
      59             :     } else {
      60         310 :         value = v;
      61             :     }
      62             : 
      63        2327 :     MOZ_ASSERT(value.isUndefined() || value.isNull() || value.isBoolean() || value.isNumber() ||
      64             :                value.isString() || value.isSymbol() || value.isObject());
      65        2327 :     return true;
      66             : }
      67             : 
      68             : static HashNumber
      69        3398 : HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs)
      70             : {
      71             :     // HashableValue::setValue normalizes values so that the SameValue relation
      72             :     // on HashableValues is the same as the == relationship on
      73             :     // value.asRawBits(). So why not just return that? Security.
      74             :     //
      75             :     // To avoid revealing GC of atoms, string-based hash codes are computed
      76             :     // from the string contents rather than any pointer; to avoid revealing
      77             :     // addresses, pointer-based hash codes are computed using the
      78             :     // HashCodeScrambler.
      79             : 
      80        3398 :     if (v.isString())
      81        2635 :         return v.toString()->asAtom().hash();
      82         763 :     if (v.isSymbol())
      83           0 :         return v.toSymbol()->hash();
      84         763 :     if (v.isObject())
      85         681 :         return hcs.scramble(v.asRawBits());
      86             : 
      87          82 :     MOZ_ASSERT(!v.isGCThing(), "do not reveal pointers via hash codes");
      88          82 :     return v.asRawBits();
      89             : }
      90             : 
      91             : HashNumber
      92        3080 : HashableValue::hash(const mozilla::HashCodeScrambler& hcs) const
      93             : {
      94        3080 :     return HashValue(value, hcs);
      95             : }
      96             : 
      97             : bool
      98        3017 : HashableValue::operator==(const HashableValue& other) const
      99             : {
     100             :     // Two HashableValues are equal if they have equal bits.
     101        3017 :     bool b = (value.asRawBits() == other.value.asRawBits());
     102             : 
     103             : #ifdef DEBUG
     104             :     bool same;
     105        3017 :     JSContext* cx = TlsContext.get();
     106        6034 :     RootedValue valueRoot(cx, value);
     107        6034 :     RootedValue otherRoot(cx, other.value);
     108        3017 :     MOZ_ASSERT(SameValue(nullptr, valueRoot, otherRoot, &same));
     109        3017 :     MOZ_ASSERT(same == b);
     110             : #endif
     111        6034 :     return b;
     112             : }
     113             : 
     114             : HashableValue
     115           0 : HashableValue::trace(JSTracer* trc) const
     116             : {
     117           0 :     HashableValue hv(*this);
     118           0 :     TraceEdge(trc, &hv.value, "key");
     119           0 :     return hv;
     120             : }
     121             : 
     122             : 
     123             : /*** MapIterator *********************************************************************************/
     124             : 
     125             : namespace {
     126             : 
     127             : } /* anonymous namespace */
     128             : 
     129             : static const ClassOps MapIteratorObjectClassOps = {
     130             :     nullptr, /* addProperty */
     131             :     nullptr, /* delProperty */
     132             :     nullptr, /* getProperty */
     133             :     nullptr, /* setProperty */
     134             :     nullptr, /* enumerate */
     135             :     nullptr, /* newEnumerate */
     136             :     nullptr, /* resolve */
     137             :     nullptr, /* mayResolve */
     138             :     MapIteratorObject::finalize
     139             : };
     140             : 
     141             : const Class MapIteratorObject::class_ = {
     142             :     "Map Iterator",
     143             :     JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount) |
     144             :     JSCLASS_FOREGROUND_FINALIZE,
     145             :     &MapIteratorObjectClassOps
     146             : };
     147             : 
     148             : const JSFunctionSpec MapIteratorObject::methods[] = {
     149             :     JS_SELF_HOSTED_FN("next", "MapIteratorNext", 0, 0),
     150             :     JS_FS_END
     151             : };
     152             : 
     153             : static inline ValueMap::Range*
     154        1070 : MapIteratorObjectRange(NativeObject* obj)
     155             : {
     156        1070 :     MOZ_ASSERT(obj->is<MapIteratorObject>());
     157        1070 :     return static_cast<ValueMap::Range*>(obj->getSlot(MapIteratorObject::RangeSlot).toPrivate());
     158             : }
     159             : 
     160             : inline MapObject::IteratorKind
     161         865 : MapIteratorObject::kind() const
     162             : {
     163         865 :     int32_t i = getSlot(KindSlot).toInt32();
     164         865 :     MOZ_ASSERT(i == MapObject::Keys || i == MapObject::Values || i == MapObject::Entries);
     165         865 :     return MapObject::IteratorKind(i);
     166             : }
     167             : 
     168             : /* static */ bool
     169          15 : GlobalObject::initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
     170             : {
     171          30 :     Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
     172          15 :     if (!base)
     173           0 :         return false;
     174          30 :     RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, base));
     175          15 :     if (!proto)
     176           0 :         return false;
     177          60 :     if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods) ||
     178          45 :         !DefineToStringTag(cx, proto, cx->names().MapIterator))
     179             :     {
     180           0 :         return false;
     181             :     }
     182          15 :     global->setReservedSlot(MAP_ITERATOR_PROTO, ObjectValue(*proto));
     183          15 :     return true;
     184             : }
     185             : 
     186             : MapIteratorObject*
     187         207 : MapIteratorObject::create(JSContext* cx, HandleObject mapobj, ValueMap* data,
     188             :                           MapObject::IteratorKind kind)
     189             : {
     190         414 :     Rooted<GlobalObject*> global(cx, &mapobj->global());
     191         414 :     Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateMapIteratorPrototype(cx, global));
     192         207 :     if (!proto)
     193           0 :         return nullptr;
     194             : 
     195         207 :     ValueMap::Range* range = cx->new_<ValueMap::Range>(data->all());
     196         207 :     if (!range)
     197           0 :         return nullptr;
     198             : 
     199         207 :     MapIteratorObject* iterobj = NewObjectWithGivenProto<MapIteratorObject>(cx, proto);
     200         207 :     if (!iterobj) {
     201           0 :         js_delete(range);
     202           0 :         return nullptr;
     203             :     }
     204         207 :     iterobj->setSlot(TargetSlot, ObjectValue(*mapobj));
     205         207 :     iterobj->setSlot(RangeSlot, PrivateValue(range));
     206         207 :     iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
     207         207 :     return iterobj;
     208             : }
     209             : 
     210             : void
     211           0 : MapIteratorObject::finalize(FreeOp* fop, JSObject* obj)
     212             : {
     213           0 :     MOZ_ASSERT(fop->onActiveCooperatingThread());
     214           0 :     fop->delete_(MapIteratorObjectRange(static_cast<NativeObject*>(obj)));
     215           0 : }
     216             : 
     217             : bool
     218        1070 : MapIteratorObject::next(Handle<MapIteratorObject*> mapIterator, HandleArrayObject resultPairObj,
     219             :                         JSContext* cx)
     220             : {
     221             :     // Check invariants for inlined _GetNextMapEntryForIterator.
     222             : 
     223             :     // The array should be tenured, so that post-barrier can be done simply.
     224        1070 :     MOZ_ASSERT(resultPairObj->isTenured());
     225             : 
     226             :     // The array elements should be fixed.
     227        1070 :     MOZ_ASSERT(resultPairObj->hasFixedElements());
     228        1070 :     MOZ_ASSERT(resultPairObj->getDenseInitializedLength() == 2);
     229        1070 :     MOZ_ASSERT(resultPairObj->getDenseCapacity() >= 2);
     230             : 
     231        1070 :     ValueMap::Range* range = MapIteratorObjectRange(mapIterator);
     232        1070 :     if (!range || range->empty()) {
     233         205 :         js_delete(range);
     234         205 :         mapIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr));
     235         205 :         return true;
     236             :     }
     237         865 :     switch (mapIterator->kind()) {
     238             :       case MapObject::Keys:
     239          12 :         resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get());
     240          12 :         break;
     241             : 
     242             :       case MapObject::Values:
     243         415 :         resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
     244         415 :         break;
     245             : 
     246             :       case MapObject::Entries: {
     247         438 :         resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get());
     248         438 :         resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
     249         438 :         break;
     250             :       }
     251             :     }
     252         865 :     range->popFront();
     253         865 :     return false;
     254             : }
     255             : 
     256             : /* static */ JSObject*
     257          15 : MapIteratorObject::createResultPair(JSContext* cx)
     258             : {
     259          30 :     RootedArrayObject resultPairObj(cx, NewDenseFullyAllocatedArray(cx, 2, nullptr, TenuredObject));
     260          15 :     if (!resultPairObj)
     261           0 :         return nullptr;
     262             : 
     263          30 :     Rooted<TaggedProto> proto(cx, resultPairObj->taggedProto());
     264          15 :     ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultPairObj->getClass(), proto);
     265          15 :     if (!group)
     266           0 :         return nullptr;
     267          15 :     resultPairObj->setGroup(group);
     268             : 
     269          15 :     resultPairObj->setDenseInitializedLength(2);
     270          15 :     resultPairObj->initDenseElement(0, NullValue());
     271          15 :     resultPairObj->initDenseElement(1, NullValue());
     272             : 
     273             :     // See comments in MapIteratorObject::next.
     274          15 :     AddTypePropertyId(cx, resultPairObj, JSID_VOID, TypeSet::UnknownType());
     275             : 
     276          15 :     return resultPairObj;
     277             : }
     278             : 
     279             : 
     280             : /*** Map *****************************************************************************************/
     281             : 
     282             : static JSObject*
     283          67 : CreateMapPrototype(JSContext* cx, JSProtoKey key)
     284             : {
     285          67 :     return GlobalObject::createBlankPrototype(cx, cx->global(), &MapObject::protoClass_);
     286             : }
     287             : 
     288             : const ClassOps MapObject::classOps_ = {
     289             :     nullptr, // addProperty
     290             :     nullptr, // delProperty
     291             :     nullptr, // getProperty
     292             :     nullptr, // setProperty
     293             :     nullptr, // enumerate
     294             :     nullptr, // newEnumerate
     295             :     nullptr, // resolve
     296             :     nullptr, // mayResolve
     297             :     finalize,
     298             :     nullptr, // call
     299             :     nullptr, // hasInstance
     300             :     nullptr, // construct
     301             :     trace
     302             : };
     303             : 
     304             : const ClassSpec MapObject::classSpec_ = {
     305             :     GenericCreateConstructor<MapObject::construct, 0, gc::AllocKind::FUNCTION>,
     306             :     CreateMapPrototype,
     307             :     nullptr,
     308             :     MapObject::staticProperties,
     309             :     MapObject::methods,
     310             :     MapObject::properties,
     311             : };
     312             : 
     313             : const Class MapObject::class_ = {
     314             :     "Map",
     315             :     JSCLASS_HAS_PRIVATE |
     316             :     JSCLASS_HAS_RESERVED_SLOTS(MapObject::SlotCount) |
     317             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Map) |
     318             :     JSCLASS_FOREGROUND_FINALIZE,
     319             :     &MapObject::classOps_,
     320             :     &MapObject::classSpec_
     321             : };
     322             : 
     323             : const Class MapObject::protoClass_ = {
     324             :     js_Object_str,
     325             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
     326             :     JS_NULL_CLASS_OPS,
     327             :     &MapObject::classSpec_
     328             : };
     329             : 
     330             : const JSPropertySpec MapObject::properties[] = {
     331             :     JS_PSG("size", size, 0),
     332             :     JS_STRING_SYM_PS(toStringTag, "Map", JSPROP_READONLY),
     333             :     JS_PS_END
     334             : };
     335             : 
     336             : const JSFunctionSpec MapObject::methods[] = {
     337             :     JS_FN("get", get, 1, 0),
     338             :     JS_FN("has", has, 1, 0),
     339             :     JS_FN("set", set, 2, 0),
     340             :     JS_FN("delete", delete_, 1, 0),
     341             :     JS_FN("keys", keys, 0, 0),
     342             :     JS_FN("values", values, 0, 0),
     343             :     JS_FN("clear", clear, 0, 0),
     344             :     JS_SELF_HOSTED_FN("forEach", "MapForEach", 2, 0),
     345             :     // MapEntries only exists to preseve the equal identity of
     346             :     // entries and @@iterator.
     347             :     JS_SELF_HOSTED_FN("entries", "MapEntries", 0, 0),
     348             :     JS_SELF_HOSTED_SYM_FN(iterator, "MapEntries", 0, 0),
     349             :     JS_FS_END
     350             : };
     351             : 
     352             : const JSPropertySpec MapObject::staticProperties[] = {
     353             :     JS_SELF_HOSTED_SYM_GET(species, "MapSpecies", 0),
     354             :     JS_PS_END
     355             : };
     356             : 
     357             : template <class Range>
     358             : static void
     359           0 : TraceKey(Range& r, const HashableValue& key, JSTracer* trc)
     360             : {
     361           0 :     HashableValue newKey = key.trace(trc);
     362             : 
     363           0 :     if (newKey.get() != key.get()) {
     364             :         // The hash function only uses the bits of the Value, so it is safe to
     365             :         // rekey even when the object or string has been modified by the GC.
     366           0 :         r.rekeyFront(newKey);
     367             :     }
     368           0 : }
     369             : 
     370             : void
     371           0 : MapObject::trace(JSTracer* trc, JSObject* obj)
     372             : {
     373           0 :     if (ValueMap* map = obj->as<MapObject>().getData()) {
     374           0 :         for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) {
     375           0 :             TraceKey(r, r.front().key, trc);
     376           0 :             TraceEdge(trc, &r.front().value, "value");
     377             :         }
     378             :     }
     379           0 : }
     380             : 
     381             : struct js::UnbarrieredHashPolicy {
     382             :     typedef Value Lookup;
     383         318 :     static HashNumber hash(const Lookup& v, const mozilla::HashCodeScrambler& hcs) {
     384         318 :         return HashValue(v, hcs);
     385             :     }
     386         161 :     static bool match(const Value& k, const Lookup& l) { return k == l; }
     387             :     static bool isEmpty(const Value& v) { return v.isMagic(JS_HASH_KEY_EMPTY); }
     388             :     static void makeEmpty(Value* vp) { vp->setMagic(JS_HASH_KEY_EMPTY); }
     389             : };
     390             : 
     391             : using NurseryKeysVector = Vector<JSObject*, 0, SystemAllocPolicy>;
     392             : 
     393             : template <typename TableObject>
     394             : static NurseryKeysVector*
     395         211 : GetNurseryKeys(TableObject* t)
     396             : {
     397         211 :     Value value = t->getReservedSlot(TableObject::NurseryKeysSlot);
     398         211 :     return reinterpret_cast<NurseryKeysVector*>(value.toPrivate());
     399             : }
     400             : 
     401             : template <typename TableObject>
     402             : static NurseryKeysVector*
     403          48 : AllocNurseryKeys(TableObject* t)
     404             : {
     405          48 :     MOZ_ASSERT(!GetNurseryKeys(t));
     406          48 :     auto keys = js_new<NurseryKeysVector>();
     407          48 :     if (!keys)
     408           0 :         return nullptr;
     409             : 
     410          48 :     t->setReservedSlot(TableObject::NurseryKeysSlot, PrivateValue(keys));
     411          48 :     return keys;
     412             : }
     413             : 
     414             : template <typename TableObject>
     415             : static void
     416          48 : DeleteNurseryKeys(TableObject* t)
     417             : {
     418          48 :     auto keys = GetNurseryKeys(t);
     419          48 :     MOZ_ASSERT(keys);
     420          48 :     js_delete(keys);
     421          48 :     t->setReservedSlot(TableObject::NurseryKeysSlot, PrivateValue(nullptr));
     422          48 : }
     423             : 
     424             : // A generic store buffer entry that traces all nursery keys for an ordered hash
     425             : // map or set.
     426             : template <typename ObjectT>
     427          48 : class js::OrderedHashTableRef : public gc::BufferableRef
     428             : {
     429             :     ObjectT* object;
     430             : 
     431             :   public:
     432          48 :     explicit OrderedHashTableRef(ObjectT* obj) : object(obj) {}
     433             : 
     434          48 :     void trace(JSTracer* trc) override {
     435          48 :         auto realTable = object->getData();
     436          48 :         auto unbarrieredTable = reinterpret_cast<typename ObjectT::UnbarrieredTable*>(realTable);
     437          48 :         NurseryKeysVector* keys = GetNurseryKeys(object);
     438          48 :         MOZ_ASSERT(keys);
     439         115 :         for (JSObject* obj : *keys) {
     440          67 :             MOZ_ASSERT(obj);
     441          67 :             Value key = ObjectValue(*obj);
     442          67 :             Value prior = key;
     443          67 :             MOZ_ASSERT(unbarrieredTable->hash(key) ==
     444             :                        realTable->hash(*reinterpret_cast<HashableValue*>(&key)));
     445          67 :             TraceManuallyBarrieredEdge(trc, &key, "ordered hash table key");
     446          67 :             unbarrieredTable->rekeyOneEntry(prior, key);
     447             :         }
     448          48 :         DeleteNurseryKeys(object);
     449          48 :     }
     450             : };
     451             : 
     452             : template <typename ObjectT>
     453             : inline static MOZ_MUST_USE bool
     454        1131 : WriteBarrierPostImpl(JSRuntime* rt, ObjectT* obj, const Value& keyValue)
     455             : {
     456        1131 :     if (MOZ_LIKELY(!keyValue.isObject()))
     457         962 :         return true;
     458             : 
     459         169 :     JSObject* key = &keyValue.toObject();
     460         169 :     if (!IsInsideNursery(key))
     461         102 :         return true;
     462             : 
     463          67 :     NurseryKeysVector* keys = GetNurseryKeys(obj);
     464          67 :     if (!keys) {
     465          48 :         keys = AllocNurseryKeys(obj);
     466          48 :         if (!keys)
     467           0 :             return false;
     468             : 
     469          48 :         key->zone()->group()->storeBuffer().putGeneric(OrderedHashTableRef<ObjectT>(obj));
     470             :     }
     471             : 
     472          67 :     if (!keys->append(key))
     473           0 :         return false;
     474             : 
     475          67 :     return true;
     476             : }
     477             : 
     478             : inline static MOZ_MUST_USE bool
     479         519 : WriteBarrierPost(JSRuntime* rt, MapObject* map, const Value& key)
     480             : {
     481         519 :     return WriteBarrierPostImpl(rt, map, key);
     482             : }
     483             : 
     484             : inline static MOZ_MUST_USE bool
     485         612 : WriteBarrierPost(JSRuntime* rt, SetObject* set, const Value& key)
     486             : {
     487         612 :     return WriteBarrierPostImpl(rt, set, key);
     488             : }
     489             : 
     490             : bool
     491           0 : MapObject::getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
     492             :                                        JS::MutableHandle<GCVector<JS::Value>> entries)
     493             : {
     494           0 :     ValueMap* map = obj->as<MapObject>().getData();
     495           0 :     if (!map)
     496           0 :         return false;
     497             : 
     498           0 :     for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) {
     499           0 :         if (!entries.append(r.front().key.get()) ||
     500           0 :             !entries.append(r.front().value))
     501             :         {
     502           0 :             return false;
     503             :         }
     504             :     }
     505             : 
     506           0 :     return true;
     507             : }
     508             : 
     509             : bool
     510           0 : MapObject::set(JSContext* cx, HandleObject obj, HandleValue k, HandleValue v)
     511             : {
     512           0 :     ValueMap* map = obj->as<MapObject>().getData();
     513           0 :     if (!map)
     514           0 :         return false;
     515             : 
     516           0 :     Rooted<HashableValue> key(cx);
     517           0 :     if (!key.setValue(cx, k))
     518           0 :         return false;
     519             : 
     520           0 :     HeapPtr<Value> rval(v);
     521           0 :     if (!WriteBarrierPost(cx->runtime(), &obj->as<MapObject>(), key.value()) ||
     522           0 :         !map->put(key, rval))
     523             :     {
     524           0 :         ReportOutOfMemory(cx);
     525           0 :         return false;
     526             :     }
     527             : 
     528           0 :     return true;
     529             : }
     530             : 
     531             : MapObject*
     532         265 : MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
     533             : {
     534         530 :     auto map = cx->make_unique<ValueMap>(cx->runtime(),
     535        1060 :                                          cx->compartment()->randomHashCodeScrambler());
     536         265 :     if (!map || !map->init()) {
     537           0 :         ReportOutOfMemory(cx);
     538           0 :         return nullptr;
     539             :     }
     540             : 
     541         265 :     MapObject* mapObj = NewObjectWithClassProto<MapObject>(cx,  proto);
     542         265 :     if (!mapObj)
     543           0 :         return nullptr;
     544             : 
     545         265 :     mapObj->setPrivate(map.release());
     546         265 :     mapObj->setReservedSlot(NurseryKeysSlot, PrivateValue(nullptr));
     547         265 :     return mapObj;
     548             : }
     549             : 
     550             : void
     551           0 : MapObject::finalize(FreeOp* fop, JSObject* obj)
     552             : {
     553           0 :     MOZ_ASSERT(fop->onActiveCooperatingThread());
     554           0 :     if (ValueMap* map = obj->as<MapObject>().getData())
     555           0 :         fop->delete_(map);
     556           0 : }
     557             : 
     558             : bool
     559         265 : MapObject::construct(JSContext* cx, unsigned argc, Value* vp)
     560             : {
     561         265 :     CallArgs args = CallArgsFromVp(argc, vp);
     562             : 
     563         265 :     if (!ThrowIfNotConstructing(cx, args, "Map"))
     564           0 :         return false;
     565             : 
     566         530 :     RootedObject proto(cx);
     567         265 :     if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
     568           0 :         return false;
     569             : 
     570         530 :     Rooted<MapObject*> obj(cx, MapObject::create(cx, proto));
     571         265 :     if (!obj)
     572           0 :         return false;
     573             : 
     574         265 :     if (!args.get(0).isNullOrUndefined()) {
     575          28 :         FixedInvokeArgs<1> args2(cx);
     576          14 :         args2[0].set(args[0]);
     577             : 
     578          28 :         RootedValue thisv(cx, ObjectValue(*obj));
     579          14 :         if (!CallSelfHostedFunction(cx, cx->names().MapConstructorInit, thisv, args2, args2.rval()))
     580           0 :             return false;
     581             :     }
     582             : 
     583         265 :     args.rval().setObject(*obj);
     584         265 :     return true;
     585             : }
     586             : 
     587             : bool
     588        2374 : MapObject::is(HandleValue v)
     589             : {
     590        2374 :     return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().as<MapObject>().getPrivate();
     591             : }
     592             : 
     593             : bool
     594           0 : MapObject::is(HandleObject o)
     595             : {
     596           0 :     return o->hasClass(&class_) && o->as<MapObject>().getPrivate();
     597             : }
     598             : 
     599             : #define ARG0_KEY(cx, args, key)                                               \
     600             :     Rooted<HashableValue> key(cx);                                            \
     601             :     if (args.length() > 0 && !key.setValue(cx, args[0]))                      \
     602             :         return false
     603             : 
     604             : ValueMap&
     605        1262 : MapObject::extract(HandleObject o)
     606             : {
     607        1262 :     MOZ_ASSERT(o->hasClass(&MapObject::class_));
     608        1262 :     return *o->as<MapObject>().getData();
     609             : }
     610             : 
     611             : ValueMap&
     612         556 : MapObject::extract(const CallArgs& args)
     613             : {
     614         556 :     MOZ_ASSERT(args.thisv().isObject());
     615         556 :     MOZ_ASSERT(args.thisv().toObject().hasClass(&MapObject::class_));
     616         556 :     return *args.thisv().toObject().as<MapObject>().getData();
     617             : }
     618             : 
     619             : uint32_t
     620          18 : MapObject::size(JSContext* cx, HandleObject obj)
     621             : {
     622          18 :     ValueMap& map = extract(obj);
     623             :     static_assert(sizeof(map.count()) <= sizeof(uint32_t),
     624             :                   "map count must be precisely representable as a JS number");
     625          18 :     return map.count();
     626             : }
     627             : 
     628             : bool
     629          18 : MapObject::size_impl(JSContext* cx, const CallArgs& args)
     630             : {
     631          36 :     RootedObject obj(cx, &args.thisv().toObject());
     632          18 :     args.rval().setNumber(size(cx, obj));
     633          36 :     return true;
     634             : }
     635             : 
     636             : bool
     637          18 : MapObject::size(JSContext* cx, unsigned argc, Value* vp)
     638             : {
     639          18 :     CallArgs args = CallArgsFromVp(argc, vp);
     640          18 :     return CallNonGenericMethod<MapObject::is, MapObject::size_impl>(cx, args);
     641             : }
     642             : 
     643             : bool
     644         536 : MapObject::get(JSContext* cx, HandleObject obj,
     645             :                HandleValue key, MutableHandleValue rval)
     646             : {
     647         536 :     ValueMap& map = extract(obj);
     648        1072 :     Rooted<HashableValue> k(cx);
     649             : 
     650         536 :     if (!k.setValue(cx, key))
     651           0 :         return false;
     652             : 
     653         536 :     if (ValueMap::Entry* p = map.get(k))
     654         457 :         rval.set(p->value);
     655             :     else
     656          79 :         rval.setUndefined();
     657             : 
     658         536 :     return true;
     659             : }
     660             : 
     661             : bool
     662         536 : MapObject::get_impl(JSContext* cx, const CallArgs& args)
     663             : {
     664        1072 :     RootedObject obj(cx, &args.thisv().toObject());
     665        1072 :     return get(cx, obj, args.get(0), args.rval());
     666             : }
     667             : 
     668             : bool
     669         536 : MapObject::get(JSContext* cx, unsigned argc, Value* vp)
     670             : {
     671         536 :     CallArgs args = CallArgsFromVp(argc, vp);
     672         536 :     return CallNonGenericMethod<MapObject::is, MapObject::get_impl>(cx, args);
     673             : }
     674             : 
     675             : bool
     676         494 : MapObject::has(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
     677             : {
     678         494 :     ValueMap& map = extract(obj);
     679         988 :     Rooted<HashableValue> k(cx);
     680             : 
     681         494 :     if (!k.setValue(cx, key))
     682           0 :         return false;
     683             : 
     684         494 :     *rval = map.has(k);
     685         494 :     return true;
     686             : }
     687             : 
     688             : bool
     689         494 : MapObject::has_impl(JSContext* cx, const CallArgs& args)
     690             : {
     691             :     bool found;
     692         988 :     RootedObject obj(cx, &args.thisv().toObject());
     693         494 :     if (has(cx, obj, args.get(0), &found)) {
     694         494 :         args.rval().setBoolean(found);
     695         494 :         return true;
     696             :     }
     697           0 :     return false;
     698             : }
     699             : 
     700             : bool
     701         494 : MapObject::has(JSContext* cx, unsigned argc, Value* vp)
     702             : {
     703         494 :     CallArgs args = CallArgsFromVp(argc, vp);
     704         494 :     return CallNonGenericMethod<MapObject::is, MapObject::has_impl>(cx, args);
     705             : }
     706             : 
     707             : bool
     708         519 : MapObject::set_impl(JSContext* cx, const CallArgs& args)
     709             : {
     710         519 :     MOZ_ASSERT(MapObject::is(args.thisv()));
     711             : 
     712         519 :     ValueMap& map = extract(args);
     713        1038 :     ARG0_KEY(cx, args, key);
     714        1038 :     HeapPtr<Value> rval(args.get(1));
     715        1038 :     if (!WriteBarrierPost(cx->runtime(), &args.thisv().toObject().as<MapObject>(), key.value()) ||
     716         519 :         !map.put(key, rval))
     717             :     {
     718           0 :         ReportOutOfMemory(cx);
     719           0 :         return false;
     720             :     }
     721             : 
     722         519 :     args.rval().set(args.thisv());
     723         519 :     return true;
     724             : }
     725             : 
     726             : bool
     727         519 : MapObject::set(JSContext* cx, unsigned argc, Value* vp)
     728             : {
     729         519 :     CallArgs args = CallArgsFromVp(argc, vp);
     730         519 :     return CallNonGenericMethod<MapObject::is, MapObject::set_impl>(cx, args);
     731             : }
     732             : 
     733             : bool
     734           0 : MapObject::delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
     735             : {
     736           0 :     ValueMap &map = extract(obj);
     737           0 :     Rooted<HashableValue> k(cx);
     738             : 
     739           0 :     if (!k.setValue(cx, key))
     740           0 :         return false;
     741             : 
     742           0 :     if (!map.remove(k, rval)) {
     743           0 :         ReportOutOfMemory(cx);
     744           0 :         return false;
     745             :     }
     746           0 :     return true;
     747             : }
     748             : 
     749             : bool
     750          37 : MapObject::delete_impl(JSContext *cx, const CallArgs& args)
     751             : {
     752             :     // MapObject::trace does not trace deleted entries. Incremental GC therefore
     753             :     // requires that no HeapPtr<Value> objects pointing to heap values be left
     754             :     // alive in the ValueMap.
     755             :     //
     756             :     // OrderedHashMap::remove() doesn't destroy the removed entry. It merely
     757             :     // calls OrderedHashMap::MapOps::makeEmpty. But that is sufficient, because
     758             :     // makeEmpty clears the value by doing e->value = Value(), and in the case
     759             :     // of a ValueMap, Value() means HeapPtr<Value>(), which is the same as
     760             :     // HeapPtr<Value>(UndefinedValue()).
     761          37 :     MOZ_ASSERT(MapObject::is(args.thisv()));
     762             : 
     763          37 :     ValueMap& map = extract(args);
     764          74 :     ARG0_KEY(cx, args, key);
     765             :     bool found;
     766          37 :     if (!map.remove(key, &found)) {
     767           0 :         ReportOutOfMemory(cx);
     768           0 :         return false;
     769             :     }
     770          37 :     args.rval().setBoolean(found);
     771          37 :     return true;
     772             : }
     773             : 
     774             : bool
     775          37 : MapObject::delete_(JSContext* cx, unsigned argc, Value* vp)
     776             : {
     777          37 :     CallArgs args = CallArgsFromVp(argc, vp);
     778          37 :     return CallNonGenericMethod<MapObject::is, MapObject::delete_impl>(cx, args);
     779             : }
     780             : 
     781             : bool
     782         207 : MapObject::iterator(JSContext* cx, IteratorKind kind,
     783             :                     HandleObject obj, MutableHandleValue iter)
     784             : {
     785         207 :     ValueMap& map = extract(obj);
     786         414 :     Rooted<JSObject*> iterobj(cx, MapIteratorObject::create(cx, obj, &map, kind));
     787         207 :     if (!iterobj)
     788           0 :         return false;
     789         207 :     iter.setObject(*iterobj);
     790         207 :     return true;
     791             : }
     792             : 
     793             : bool
     794         207 : MapObject::iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind)
     795             : {
     796         414 :     RootedObject obj(cx, &args.thisv().toObject());
     797         414 :     return iterator(cx, kind, obj, args.rval());
     798             : }
     799             : 
     800             : bool
     801           7 : MapObject::keys_impl(JSContext* cx, const CallArgs& args)
     802             : {
     803           7 :     return iterator_impl(cx, args, Keys);
     804             : }
     805             : 
     806             : bool
     807           7 : MapObject::keys(JSContext* cx, unsigned argc, Value* vp)
     808             : {
     809           7 :     CallArgs args = CallArgsFromVp(argc, vp);
     810           7 :     return CallNonGenericMethod(cx, is, keys_impl, args);
     811             : }
     812             : 
     813             : bool
     814         116 : MapObject::values_impl(JSContext* cx, const CallArgs& args)
     815             : {
     816         116 :     return iterator_impl(cx, args, Values);
     817             : }
     818             : 
     819             : bool
     820         116 : MapObject::values(JSContext* cx, unsigned argc, Value* vp)
     821             : {
     822         116 :     CallArgs args = CallArgsFromVp(argc, vp);
     823         116 :     return CallNonGenericMethod(cx, is, values_impl, args);
     824             : }
     825             : 
     826             : bool
     827          84 : MapObject::entries_impl(JSContext* cx, const CallArgs& args)
     828             : {
     829          84 :     return iterator_impl(cx, args, Entries);
     830             : }
     831             : 
     832             : bool
     833          84 : MapObject::entries(JSContext* cx, unsigned argc, Value* vp)
     834             : {
     835          84 :     CallArgs args = CallArgsFromVp(argc, vp);
     836          84 :     return CallNonGenericMethod(cx, is, entries_impl, args);
     837             : }
     838             : 
     839             : bool
     840           7 : MapObject::clear_impl(JSContext* cx, const CallArgs& args)
     841             : {
     842          14 :     RootedObject obj(cx, &args.thisv().toObject());
     843           7 :     args.rval().setUndefined();
     844          14 :     return clear(cx, obj);
     845             : }
     846             : 
     847             : bool
     848           7 : MapObject::clear(JSContext* cx, unsigned argc, Value* vp)
     849             : {
     850           7 :     CallArgs args = CallArgsFromVp(argc, vp);
     851           7 :     return CallNonGenericMethod(cx, is, clear_impl, args);
     852             : }
     853             : 
     854             : bool
     855           7 : MapObject::clear(JSContext* cx, HandleObject obj)
     856             : {
     857           7 :     ValueMap& map = extract(obj);
     858           7 :     if (!map.clear()) {
     859           0 :         ReportOutOfMemory(cx);
     860           0 :         return false;
     861             :     }
     862           7 :     return true;
     863             : }
     864             : 
     865             : 
     866             : /*** SetIterator *********************************************************************************/
     867             : 
     868             : static const ClassOps SetIteratorObjectClassOps = {
     869             :     nullptr, /* addProperty */
     870             :     nullptr, /* delProperty */
     871             :     nullptr, /* getProperty */
     872             :     nullptr, /* setProperty */
     873             :     nullptr, /* enumerate */
     874             :     nullptr, /* newEnumerate */
     875             :     nullptr, /* resolve */
     876             :     nullptr, /* mayResolve */
     877             :     SetIteratorObject::finalize
     878             : };
     879             : 
     880             : const Class SetIteratorObject::class_ = {
     881             :     "Set Iterator",
     882             :     JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount) |
     883             :     JSCLASS_FOREGROUND_FINALIZE,
     884             :     &SetIteratorObjectClassOps
     885             : };
     886             : 
     887             : const JSFunctionSpec SetIteratorObject::methods[] = {
     888             :     JS_SELF_HOSTED_FN("next", "SetIteratorNext", 0, 0),
     889             :     JS_FS_END
     890             : };
     891             : 
     892             : static inline ValueSet::Range*
     893         255 : SetIteratorObjectRange(NativeObject* obj)
     894             : {
     895         255 :     MOZ_ASSERT(obj->is<SetIteratorObject>());
     896         255 :     return static_cast<ValueSet::Range*>(obj->getSlot(SetIteratorObject::RangeSlot).toPrivate());
     897             : }
     898             : 
     899             : inline SetObject::IteratorKind
     900             : SetIteratorObject::kind() const
     901             : {
     902             :     int32_t i = getSlot(KindSlot).toInt32();
     903             :     MOZ_ASSERT(i == SetObject::Values || i == SetObject::Entries);
     904             :     return SetObject::IteratorKind(i);
     905             : }
     906             : 
     907             : /* static */ bool
     908           8 : GlobalObject::initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
     909             : {
     910          16 :     Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
     911           8 :     if (!base)
     912           0 :         return false;
     913          16 :     RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, base));
     914           8 :     if (!proto)
     915           0 :         return false;
     916          32 :     if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods) ||
     917          24 :         !DefineToStringTag(cx, proto, cx->names().SetIterator))
     918             :     {
     919           0 :         return false;
     920             :     }
     921           8 :     global->setReservedSlot(SET_ITERATOR_PROTO, ObjectValue(*proto));
     922           8 :     return true;
     923             : }
     924             : 
     925             : SetIteratorObject*
     926          82 : SetIteratorObject::create(JSContext* cx, HandleObject setobj, ValueSet* data,
     927             :                           SetObject::IteratorKind kind)
     928             : {
     929          82 :     MOZ_ASSERT(kind != SetObject::Keys);
     930             : 
     931         164 :     Rooted<GlobalObject*> global(cx, &setobj->global());
     932         164 :     Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateSetIteratorPrototype(cx, global));
     933          82 :     if (!proto)
     934           0 :         return nullptr;
     935             : 
     936          82 :     ValueSet::Range* range = cx->new_<ValueSet::Range>(data->all());
     937          82 :     if (!range)
     938           0 :         return nullptr;
     939             : 
     940          82 :     SetIteratorObject* iterobj = NewObjectWithGivenProto<SetIteratorObject>(cx, proto);
     941          82 :     if (!iterobj) {
     942           0 :         js_delete(range);
     943           0 :         return nullptr;
     944             :     }
     945          82 :     iterobj->setSlot(TargetSlot, ObjectValue(*setobj));
     946          82 :     iterobj->setSlot(RangeSlot, PrivateValue(range));
     947          82 :     iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
     948          82 :     return iterobj;
     949             : }
     950             : 
     951             : void
     952           0 : SetIteratorObject::finalize(FreeOp* fop, JSObject* obj)
     953             : {
     954           0 :     MOZ_ASSERT(fop->onActiveCooperatingThread());
     955           0 :     fop->delete_(SetIteratorObjectRange(static_cast<NativeObject*>(obj)));
     956           0 : }
     957             : 
     958             : bool
     959         255 : SetIteratorObject::next(Handle<SetIteratorObject*> setIterator, HandleArrayObject resultObj,
     960             :                         JSContext* cx)
     961             : {
     962             :     // Check invariants for inlined _GetNextSetEntryForIterator.
     963             : 
     964             :     // The array should be tenured, so that post-barrier can be done simply.
     965         255 :     MOZ_ASSERT(resultObj->isTenured());
     966             : 
     967             :     // The array elements should be fixed.
     968         255 :     MOZ_ASSERT(resultObj->hasFixedElements());
     969         255 :     MOZ_ASSERT(resultObj->getDenseInitializedLength() == 1);
     970         255 :     MOZ_ASSERT(resultObj->getDenseCapacity() >= 1);
     971             : 
     972         255 :     ValueSet::Range* range = SetIteratorObjectRange(setIterator);
     973         255 :     if (!range || range->empty()) {
     974          73 :         js_delete(range);
     975          73 :         setIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr));
     976          73 :         return true;
     977             :     }
     978         182 :     resultObj->setDenseElementWithType(cx, 0, range->front().get());
     979         182 :     range->popFront();
     980         182 :     return false;
     981             : }
     982             : 
     983             : /* static */ JSObject*
     984           8 : SetIteratorObject::createResult(JSContext* cx)
     985             : {
     986          16 :     RootedArrayObject resultObj(cx, NewDenseFullyAllocatedArray(cx, 1, nullptr, TenuredObject));
     987           8 :     if (!resultObj)
     988           0 :         return nullptr;
     989             : 
     990          16 :     Rooted<TaggedProto> proto(cx, resultObj->taggedProto());
     991           8 :     ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultObj->getClass(), proto);
     992           8 :     if (!group)
     993           0 :         return nullptr;
     994           8 :     resultObj->setGroup(group);
     995             : 
     996           8 :     resultObj->setDenseInitializedLength(1);
     997           8 :     resultObj->initDenseElement(0, NullValue());
     998             : 
     999             :     // See comments in SetIteratorObject::next.
    1000           8 :     AddTypePropertyId(cx, resultObj, JSID_VOID, TypeSet::UnknownType());
    1001             : 
    1002           8 :     return resultObj;
    1003             : }
    1004             : 
    1005             : 
    1006             : /*** Set *****************************************************************************************/
    1007             : 
    1008             : static JSObject*
    1009          48 : CreateSetPrototype(JSContext* cx, JSProtoKey key)
    1010             : {
    1011          48 :     return GlobalObject::createBlankPrototype(cx, cx->global(), &SetObject::protoClass_);
    1012             : }
    1013             : 
    1014             : const ClassOps SetObject::classOps_ = {
    1015             :     nullptr, // addProperty
    1016             :     nullptr, // delProperty
    1017             :     nullptr, // getProperty
    1018             :     nullptr, // setProperty
    1019             :     nullptr, // enumerate
    1020             :     nullptr, // newEnumerate
    1021             :     nullptr, // resolve
    1022             :     nullptr, // mayResolve
    1023             :     finalize,
    1024             :     nullptr, // call
    1025             :     nullptr, // hasInstance
    1026             :     nullptr, // construct
    1027             :     trace
    1028             : };
    1029             : 
    1030             : const ClassSpec SetObject::classSpec_ = {
    1031             :     GenericCreateConstructor<SetObject::construct, 0, gc::AllocKind::FUNCTION>,
    1032             :     CreateSetPrototype,
    1033             :     nullptr,
    1034             :     SetObject::staticProperties,
    1035             :     SetObject::methods,
    1036             :     SetObject::properties,
    1037             : };
    1038             : 
    1039             : const Class SetObject::class_ = {
    1040             :     "Set",
    1041             :     JSCLASS_HAS_PRIVATE |
    1042             :     JSCLASS_HAS_RESERVED_SLOTS(SetObject::SlotCount) |
    1043             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Set) |
    1044             :     JSCLASS_FOREGROUND_FINALIZE,
    1045             :     &SetObject::classOps_,
    1046             :     &SetObject::classSpec_,
    1047             : };
    1048             : 
    1049             : const Class SetObject::protoClass_ = {
    1050             :     js_Object_str,
    1051             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
    1052             :     JS_NULL_CLASS_OPS,
    1053             :     &SetObject::classSpec_
    1054             : };
    1055             : 
    1056             : const JSPropertySpec SetObject::properties[] = {
    1057             :     JS_PSG("size", size, 0),
    1058             :     JS_STRING_SYM_PS(toStringTag, "Set", JSPROP_READONLY),
    1059             :     JS_PS_END
    1060             : };
    1061             : 
    1062             : const JSFunctionSpec SetObject::methods[] = {
    1063             :     JS_FN("has", has, 1, 0),
    1064             :     JS_FN("add", add, 1, 0),
    1065             :     JS_FN("delete", delete_, 1, 0),
    1066             :     JS_FN("entries", entries, 0, 0),
    1067             :     JS_FN("clear", clear, 0, 0),
    1068             :     JS_SELF_HOSTED_FN("forEach", "SetForEach", 2, 0),
    1069             :     // SetValues only exists to preseve the equal identity of
    1070             :     // values, keys and @@iterator.
    1071             :     JS_SELF_HOSTED_FN("values", "SetValues", 0, 0),
    1072             :     JS_SELF_HOSTED_FN("keys", "SetValues", 0, 0),
    1073             :     JS_SELF_HOSTED_SYM_FN(iterator, "SetValues", 0, 0),
    1074             :     JS_FS_END
    1075             : };
    1076             : 
    1077             : const JSPropertySpec SetObject::staticProperties[] = {
    1078             :     JS_SELF_HOSTED_SYM_GET(species, "SetSpecies", 0),
    1079             :     JS_PS_END
    1080             : };
    1081             : 
    1082             : bool
    1083           0 : SetObject::keys(JSContext* cx, HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> keys)
    1084             : {
    1085           0 :     ValueSet* set = obj->as<SetObject>().getData();
    1086           0 :     if (!set)
    1087           0 :         return false;
    1088             : 
    1089           0 :     for (ValueSet::Range r = set->all(); !r.empty(); r.popFront()) {
    1090           0 :         if (!keys.append(r.front().get()))
    1091           0 :             return false;
    1092             :     }
    1093             : 
    1094           0 :     return true;
    1095             : }
    1096             : 
    1097             : bool
    1098           0 : SetObject::add(JSContext* cx, HandleObject obj, HandleValue k)
    1099             : {
    1100           0 :     ValueSet* set = obj->as<SetObject>().getData();
    1101           0 :     if (!set)
    1102           0 :         return false;
    1103             : 
    1104           0 :     Rooted<HashableValue> key(cx);
    1105           0 :     if (!key.setValue(cx, k))
    1106           0 :         return false;
    1107             : 
    1108           0 :     if (!WriteBarrierPost(cx->runtime(), &obj->as<SetObject>(), key.value()) ||
    1109           0 :         !set->put(key))
    1110             :     {
    1111           0 :         ReportOutOfMemory(cx);
    1112           0 :         return false;
    1113             :     }
    1114           0 :     return true;
    1115             : }
    1116             : 
    1117             : SetObject*
    1118         143 : SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
    1119             : {
    1120         286 :     auto set = cx->make_unique<ValueSet>(cx->runtime(),
    1121         572 :                                          cx->compartment()->randomHashCodeScrambler());
    1122         143 :     if (!set || !set->init()) {
    1123           0 :         ReportOutOfMemory(cx);
    1124           0 :         return nullptr;
    1125             :     }
    1126             : 
    1127         143 :     SetObject* obj = NewObjectWithClassProto<SetObject>(cx, proto);
    1128         143 :     if (!obj)
    1129           0 :         return nullptr;
    1130             : 
    1131         143 :     obj->setPrivate(set.release());
    1132         143 :     obj->setReservedSlot(NurseryKeysSlot, PrivateValue(nullptr));
    1133         143 :     return obj;
    1134             : }
    1135             : 
    1136             : void
    1137           0 : SetObject::trace(JSTracer* trc, JSObject* obj)
    1138             : {
    1139           0 :     SetObject* setobj = static_cast<SetObject*>(obj);
    1140           0 :     if (ValueSet* set = setobj->getData()) {
    1141           0 :         for (ValueSet::Range r = set->all(); !r.empty(); r.popFront())
    1142           0 :             TraceKey(r, r.front(), trc);
    1143             :     }
    1144           0 : }
    1145             : 
    1146             : void
    1147           0 : SetObject::finalize(FreeOp* fop, JSObject* obj)
    1148             : {
    1149           0 :     MOZ_ASSERT(fop->onActiveCooperatingThread());
    1150           0 :     SetObject* setobj = static_cast<SetObject*>(obj);
    1151           0 :     if (ValueSet* set = setobj->getData())
    1152           0 :         fop->delete_(set);
    1153           0 : }
    1154             : 
    1155             : bool
    1156          52 : SetObject::isBuiltinAdd(HandleValue add, JSContext* cx)
    1157             : {
    1158          52 :     return IsNativeFunction(add, SetObject::add);
    1159             : }
    1160             : 
    1161             : bool
    1162         143 : SetObject::construct(JSContext* cx, unsigned argc, Value* vp)
    1163             : {
    1164         143 :     CallArgs args = CallArgsFromVp(argc, vp);
    1165             : 
    1166         143 :     if (!ThrowIfNotConstructing(cx, args, "Set"))
    1167           0 :         return false;
    1168             : 
    1169         286 :     RootedObject proto(cx);
    1170         143 :     if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
    1171           0 :         return false;
    1172             : 
    1173         286 :     Rooted<SetObject*> obj(cx, SetObject::create(cx, proto));
    1174         143 :     if (!obj)
    1175           0 :         return false;
    1176             : 
    1177         143 :     if (!args.get(0).isNullOrUndefined()) {
    1178         122 :         RootedValue iterable(cx, args[0]);
    1179          61 :         bool optimized = false;
    1180          61 :         if (!IsOptimizableInitForSet<GlobalObject::getOrCreateSetPrototype, isBuiltinAdd>(cx, obj, iterable, &optimized))
    1181           0 :             return false;
    1182             : 
    1183          61 :         if (optimized) {
    1184         104 :             RootedValue keyVal(cx);
    1185         104 :             Rooted<HashableValue> key(cx);
    1186          52 :             ValueSet* set = obj->getData();
    1187          52 :             ArrayObject* array = &iterable.toObject().as<ArrayObject>();
    1188         371 :             for (uint32_t index = 0; index < array->getDenseInitializedLength(); ++index) {
    1189         319 :                 keyVal.set(array->getDenseElement(index));
    1190         319 :                 MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
    1191             : 
    1192         319 :                 if (!key.setValue(cx, keyVal))
    1193           0 :                     return false;
    1194         638 :                 if (!WriteBarrierPost(cx->runtime(), obj, keyVal) ||
    1195         319 :                     !set->put(key))
    1196             :                 {
    1197           0 :                     ReportOutOfMemory(cx);
    1198           0 :                     return false;
    1199             :                 }
    1200             :             }
    1201             :         } else {
    1202          18 :             FixedInvokeArgs<1> args2(cx);
    1203           9 :             args2[0].set(args[0]);
    1204             : 
    1205          18 :             RootedValue thisv(cx, ObjectValue(*obj));
    1206           9 :             if (!CallSelfHostedFunction(cx, cx->names().SetConstructorInit, thisv, args2, args2.rval()))
    1207           0 :                 return false;
    1208             :         }
    1209             :     }
    1210             : 
    1211         143 :     args.rval().setObject(*obj);
    1212         143 :     return true;
    1213             : }
    1214             : 
    1215             : bool
    1216         959 : SetObject::is(HandleValue v)
    1217             : {
    1218         959 :     return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().as<SetObject>().getPrivate();
    1219             : }
    1220             : 
    1221             : bool
    1222           0 : SetObject::is(HandleObject o)
    1223             : {
    1224           0 :     return o->hasClass(&class_) && o->as<SetObject>().getPrivate();
    1225             : }
    1226             : 
    1227             : ValueSet &
    1228           0 : SetObject::extract(HandleObject o)
    1229             : {
    1230           0 :     MOZ_ASSERT(o->hasClass(&SetObject::class_));
    1231           0 :     return *o->as<SetObject>().getData();
    1232             : }
    1233             : 
    1234             : ValueSet &
    1235         438 : SetObject::extract(const CallArgs& args)
    1236             : {
    1237         438 :     MOZ_ASSERT(args.thisv().isObject());
    1238         438 :     MOZ_ASSERT(args.thisv().toObject().hasClass(&SetObject::class_));
    1239         438 :     return *static_cast<SetObject&>(args.thisv().toObject()).getData();
    1240             : }
    1241             : 
    1242             : uint32_t
    1243           0 : SetObject::size(JSContext *cx, HandleObject obj)
    1244             : {
    1245           0 :     MOZ_ASSERT(SetObject::is(obj));
    1246           0 :     ValueSet &set = extract(obj);
    1247             :     static_assert(sizeof(set.count()) <= sizeof(uint32_t),
    1248             :                   "set count must be precisely representable as a JS number");
    1249           0 :     return set.count();
    1250             : }
    1251             : 
    1252             : bool
    1253          12 : SetObject::size_impl(JSContext* cx, const CallArgs& args)
    1254             : {
    1255          12 :     MOZ_ASSERT(is(args.thisv()));
    1256             : 
    1257          12 :     ValueSet& set = extract(args);
    1258             :     static_assert(sizeof(set.count()) <= sizeof(uint32_t),
    1259             :                   "set count must be precisely representable as a JS number");
    1260          12 :     args.rval().setNumber(set.count());
    1261          12 :     return true;
    1262             : }
    1263             : 
    1264             : bool
    1265          12 : SetObject::size(JSContext* cx, unsigned argc, Value* vp)
    1266             : {
    1267          12 :     CallArgs args = CallArgsFromVp(argc, vp);
    1268          12 :     return CallNonGenericMethod<SetObject::is, SetObject::size_impl>(cx, args);
    1269             : }
    1270             : 
    1271             : bool
    1272         116 : SetObject::has_impl(JSContext* cx, const CallArgs& args)
    1273             : {
    1274         116 :     MOZ_ASSERT(is(args.thisv()));
    1275             : 
    1276         116 :     ValueSet& set = extract(args);
    1277         232 :     ARG0_KEY(cx, args, key);
    1278         116 :     args.rval().setBoolean(set.has(key));
    1279         116 :     return true;
    1280             : }
    1281             : 
    1282             : bool
    1283           0 : SetObject::has(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
    1284             : {
    1285           0 :     MOZ_ASSERT(SetObject::is(obj));
    1286             : 
    1287           0 :     ValueSet &set = extract(obj);
    1288           0 :     Rooted<HashableValue> k(cx);
    1289             : 
    1290           0 :     if (!k.setValue(cx, key))
    1291           0 :         return false;
    1292             : 
    1293           0 :     *rval = set.has(k);
    1294           0 :     return true;
    1295             : }
    1296             : 
    1297             : bool
    1298         116 : SetObject::has(JSContext *cx, unsigned argc, Value *vp)
    1299             : {
    1300         116 :     CallArgs args = CallArgsFromVp(argc, vp);
    1301         116 :     return CallNonGenericMethod<SetObject::is, SetObject::has_impl>(cx, args);
    1302             : }
    1303             : 
    1304             : bool
    1305         293 : SetObject::add_impl(JSContext* cx, const CallArgs& args)
    1306             : {
    1307         293 :     MOZ_ASSERT(is(args.thisv()));
    1308             : 
    1309         293 :     ValueSet& set = extract(args);
    1310         586 :     ARG0_KEY(cx, args, key);
    1311         586 :     if (!WriteBarrierPost(cx->runtime(), &args.thisv().toObject().as<SetObject>(), key.value()) ||
    1312         293 :         !set.put(key))
    1313             :     {
    1314           0 :         ReportOutOfMemory(cx);
    1315           0 :         return false;
    1316             :     }
    1317         293 :     args.rval().set(args.thisv());
    1318         293 :     return true;
    1319             : }
    1320             : 
    1321             : bool
    1322         293 : SetObject::add(JSContext* cx, unsigned argc, Value* vp)
    1323             : {
    1324         293 :     CallArgs args = CallArgsFromVp(argc, vp);
    1325         293 :     return CallNonGenericMethod<SetObject::is, SetObject::add_impl>(cx, args);
    1326             : }
    1327             : 
    1328             : bool
    1329           0 : SetObject::delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
    1330             : {
    1331           0 :     MOZ_ASSERT(SetObject::is(obj));
    1332             : 
    1333           0 :     ValueSet &set = extract(obj);
    1334           0 :     Rooted<HashableValue> k(cx);
    1335             : 
    1336           0 :     if (!k.setValue(cx, key))
    1337           0 :         return false;
    1338             : 
    1339           0 :     if (!set.remove(k, rval)) {
    1340           0 :         ReportOutOfMemory(cx);
    1341           0 :         return false;
    1342             :     }
    1343           0 :     return true;
    1344             : }
    1345             : 
    1346             : bool
    1347          17 : SetObject::delete_impl(JSContext *cx, const CallArgs& args)
    1348             : {
    1349          17 :     MOZ_ASSERT(is(args.thisv()));
    1350             : 
    1351          17 :     ValueSet& set = extract(args);
    1352          34 :     ARG0_KEY(cx, args, key);
    1353             :     bool found;
    1354          17 :     if (!set.remove(key, &found)) {
    1355           0 :         ReportOutOfMemory(cx);
    1356           0 :         return false;
    1357             :     }
    1358          17 :     args.rval().setBoolean(found);
    1359          17 :     return true;
    1360             : }
    1361             : 
    1362             : bool
    1363          17 : SetObject::delete_(JSContext* cx, unsigned argc, Value* vp)
    1364             : {
    1365          17 :     CallArgs args = CallArgsFromVp(argc, vp);
    1366          17 :     return CallNonGenericMethod<SetObject::is, SetObject::delete_impl>(cx, args);
    1367             : }
    1368             : 
    1369             : bool
    1370           0 : SetObject::iterator(JSContext *cx, IteratorKind kind,
    1371             :                     HandleObject obj, MutableHandleValue iter)
    1372             : {
    1373           0 :     MOZ_ASSERT(SetObject::is(obj));
    1374           0 :     ValueSet &set = extract(obj);
    1375           0 :     Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, obj, &set, kind));
    1376           0 :     if (!iterobj)
    1377           0 :         return false;
    1378           0 :     iter.setObject(*iterobj);
    1379           0 :     return true;
    1380             : }
    1381             : 
    1382             : bool
    1383          82 : SetObject::iterator_impl(JSContext *cx, const CallArgs& args, IteratorKind kind)
    1384             : {
    1385         164 :     Rooted<SetObject*> setobj(cx, &args.thisv().toObject().as<SetObject>());
    1386          82 :     ValueSet& set = *setobj->getData();
    1387         164 :     Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, setobj, &set, kind));
    1388          82 :     if (!iterobj)
    1389           0 :         return false;
    1390          82 :     args.rval().setObject(*iterobj);
    1391          82 :     return true;
    1392             : }
    1393             : 
    1394             : bool
    1395          82 : SetObject::values_impl(JSContext* cx, const CallArgs& args)
    1396             : {
    1397          82 :     return iterator_impl(cx, args, Values);
    1398             : }
    1399             : 
    1400             : bool
    1401          82 : SetObject::values(JSContext* cx, unsigned argc, Value* vp)
    1402             : {
    1403          82 :     CallArgs args = CallArgsFromVp(argc, vp);
    1404          82 :     return CallNonGenericMethod(cx, is, values_impl, args);
    1405             : }
    1406             : 
    1407             : bool
    1408           0 : SetObject::entries_impl(JSContext* cx, const CallArgs& args)
    1409             : {
    1410           0 :     return iterator_impl(cx, args, Entries);
    1411             : }
    1412             : 
    1413             : bool
    1414           0 : SetObject::entries(JSContext* cx, unsigned argc, Value* vp)
    1415             : {
    1416           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1417           0 :     return CallNonGenericMethod(cx, is, entries_impl, args);
    1418             : }
    1419             : 
    1420             : bool
    1421           0 : SetObject::clear(JSContext *cx, HandleObject obj)
    1422             : {
    1423           0 :     MOZ_ASSERT(SetObject::is(obj));
    1424           0 :     ValueSet &set = extract(obj);
    1425           0 :     if (!set.clear()) {
    1426           0 :         ReportOutOfMemory(cx);
    1427           0 :         return false;
    1428             :     }
    1429           0 :     return true;
    1430             : }
    1431             : 
    1432             : bool
    1433           1 : SetObject::clear_impl(JSContext *cx, const CallArgs& args)
    1434             : {
    1435           2 :     Rooted<SetObject*> setobj(cx, &args.thisv().toObject().as<SetObject>());
    1436           1 :     if (!setobj->getData()->clear()) {
    1437           0 :         ReportOutOfMemory(cx);
    1438           0 :         return false;
    1439             :     }
    1440           1 :     args.rval().setUndefined();
    1441           1 :     return true;
    1442             : }
    1443             : 
    1444             : bool
    1445           1 : SetObject::clear(JSContext* cx, unsigned argc, Value* vp)
    1446             : {
    1447           1 :     CallArgs args = CallArgsFromVp(argc, vp);
    1448           1 :     return CallNonGenericMethod(cx, is, clear_impl, args);
    1449             : }
    1450             : 
    1451             : /*** JS static utility functions *********************************************/
    1452             : 
    1453             : static bool
    1454           0 : forEach(const char* funcName, JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisArg)
    1455             : {
    1456           0 :     CHECK_REQUEST(cx);
    1457             : 
    1458           0 :     RootedId forEachId(cx, NameToId(cx->names().forEach));
    1459           0 :     RootedFunction forEachFunc(cx, JS::GetSelfHostedFunction(cx, funcName, forEachId, 2));
    1460           0 :     if (!forEachFunc)
    1461           0 :         return false;
    1462             : 
    1463           0 :     RootedValue fval(cx, ObjectValue(*forEachFunc));
    1464           0 :     return Call(cx, fval, obj, callbackFn, thisArg, &fval);
    1465             : }
    1466             : 
    1467             : // Handles Clear/Size for public jsapi map/set access
    1468             : template<typename RetT>
    1469             : RetT
    1470           0 : CallObjFunc(RetT(*ObjFunc)(JSContext*, HandleObject), JSContext* cx, HandleObject obj)
    1471             : {
    1472           0 :     CHECK_REQUEST(cx);
    1473           0 :     assertSameCompartment(cx, obj);
    1474             : 
    1475             :     // Always unwrap, in case this is an xray or cross-compartment wrapper.
    1476           0 :     RootedObject unwrappedObj(cx);
    1477           0 :     unwrappedObj = UncheckedUnwrap(obj);
    1478             : 
    1479             :     // Enter the compartment of the backing object before calling functions on
    1480             :     // it.
    1481           0 :     JSAutoCompartment ac(cx, unwrappedObj);
    1482           0 :     return ObjFunc(cx, unwrappedObj);
    1483             : }
    1484             : 
    1485             : // Handles Has/Delete for public jsapi map/set access
    1486             : bool
    1487           0 : CallObjFunc(bool(*ObjFunc)(JSContext *cx, HandleObject obj, HandleValue key, bool *rval),
    1488             :             JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
    1489             : {
    1490           0 :     CHECK_REQUEST(cx);
    1491           0 :     assertSameCompartment(cx, obj, key);
    1492             : 
    1493             :     // Always unwrap, in case this is an xray or cross-compartment wrapper.
    1494           0 :     RootedObject unwrappedObj(cx);
    1495           0 :     unwrappedObj = UncheckedUnwrap(obj);
    1496           0 :     JSAutoCompartment ac(cx, unwrappedObj);
    1497             : 
    1498             :     // If we're working with a wrapped map/set, rewrap the key into the
    1499             :     // compartment of the unwrapped map/set.
    1500           0 :     RootedValue wrappedKey(cx, key);
    1501           0 :     if (obj != unwrappedObj) {
    1502           0 :         if (!JS_WrapValue(cx, &wrappedKey))
    1503           0 :             return false;
    1504             :     }
    1505           0 :     return ObjFunc(cx, unwrappedObj, wrappedKey, rval);
    1506             : }
    1507             : 
    1508             : // Handles iterator generation for public jsapi map/set access
    1509             : template<typename Iter>
    1510             : bool
    1511           0 : CallObjFunc(bool(*ObjFunc)(JSContext* cx, Iter kind,
    1512             :                            HandleObject obj, MutableHandleValue iter),
    1513             :             JSContext *cx, Iter iterType, HandleObject obj, MutableHandleValue rval)
    1514             : {
    1515           0 :     CHECK_REQUEST(cx);
    1516           0 :     assertSameCompartment(cx, obj);
    1517             : 
    1518             :     // Always unwrap, in case this is an xray or cross-compartment wrapper.
    1519           0 :     RootedObject unwrappedObj(cx);
    1520           0 :     unwrappedObj = UncheckedUnwrap(obj);
    1521             :     {
    1522             :         // Retrieve the iterator while in the unwrapped map/set's compartment,
    1523             :         // otherwise we'll crash on a compartment assert.
    1524           0 :         JSAutoCompartment ac(cx, unwrappedObj);
    1525           0 :         if (!ObjFunc(cx, iterType, unwrappedObj, rval))
    1526           0 :             return false;
    1527             :     }
    1528             : 
    1529             :     // If the caller is in a different compartment than the map/set, rewrap the
    1530             :     // iterator object into the caller's compartment.
    1531           0 :     if (obj != unwrappedObj) {
    1532           0 :         if (!JS_WrapValue(cx, rval))
    1533           0 :             return false;
    1534             :     }
    1535           0 :     return true;
    1536             : }
    1537             : 
    1538             : /*** JS public APIs **********************************************************/
    1539             : 
    1540             : JS_PUBLIC_API(JSObject*)
    1541           0 : JS::NewMapObject(JSContext* cx)
    1542             : {
    1543           0 :     return MapObject::create(cx);
    1544             : }
    1545             : 
    1546             : JS_PUBLIC_API(uint32_t)
    1547           0 : JS::MapSize(JSContext* cx, HandleObject obj)
    1548             : {
    1549           0 :     return CallObjFunc<uint32_t>(&MapObject::size, cx, obj);
    1550             : }
    1551             : 
    1552             : JS_PUBLIC_API(bool)
    1553           0 : JS::MapGet(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval)
    1554             : {
    1555           0 :     CHECK_REQUEST(cx);
    1556           0 :     assertSameCompartment(cx, obj, key, rval);
    1557             : 
    1558             :     // Unwrap the object, and enter its compartment. If object isn't wrapped,
    1559             :     // this is essentially a noop.
    1560           0 :     RootedObject unwrappedObj(cx);
    1561           0 :     unwrappedObj = UncheckedUnwrap(obj);
    1562             :     {
    1563           0 :         JSAutoCompartment ac(cx, unwrappedObj);
    1564           0 :         RootedValue wrappedKey(cx, key);
    1565             : 
    1566             :         // If we passed in a wrapper, wrap our key into its compartment now.
    1567           0 :         if (obj != unwrappedObj) {
    1568           0 :             if (!JS_WrapValue(cx, &wrappedKey))
    1569           0 :                 return false;
    1570             :         }
    1571           0 :         if (!MapObject::get(cx, unwrappedObj, wrappedKey, rval))
    1572           0 :             return false;
    1573             :     }
    1574             : 
    1575             :     // If we passed in a wrapper, wrap our return value on the way out.
    1576           0 :     if (obj != unwrappedObj) {
    1577           0 :         if (!JS_WrapValue(cx, rval))
    1578           0 :             return false;
    1579             :     }
    1580           0 :     return true;
    1581             : }
    1582             : 
    1583             : JS_PUBLIC_API(bool)
    1584           0 : JS::MapSet(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val)
    1585             : {
    1586           0 :     CHECK_REQUEST(cx);
    1587           0 :     assertSameCompartment(cx, obj, key, val);
    1588             : 
    1589             :     // Unwrap the object, and enter its compartment. If object isn't wrapped,
    1590             :     // this is essentially a noop.
    1591           0 :     RootedObject unwrappedObj(cx);
    1592           0 :     unwrappedObj = UncheckedUnwrap(obj);
    1593             :     {
    1594           0 :         JSAutoCompartment ac(cx, unwrappedObj);
    1595             : 
    1596             :         // If we passed in a wrapper, wrap both key and value before adding to
    1597             :         // the map
    1598           0 :         RootedValue wrappedKey(cx, key);
    1599           0 :         RootedValue wrappedValue(cx, val);
    1600           0 :         if (obj != unwrappedObj) {
    1601           0 :             if (!JS_WrapValue(cx, &wrappedKey) ||
    1602           0 :                 !JS_WrapValue(cx, &wrappedValue)) {
    1603           0 :                 return false;
    1604             :             }
    1605             :         }
    1606           0 :         return MapObject::set(cx, unwrappedObj, wrappedKey, wrappedValue);
    1607             :     }
    1608             : }
    1609             : 
    1610             : JS_PUBLIC_API(bool)
    1611           0 : JS::MapHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
    1612             : {
    1613           0 :     return CallObjFunc(MapObject::has, cx, obj, key, rval);
    1614             : }
    1615             : 
    1616             : JS_PUBLIC_API(bool)
    1617           0 : JS::MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool* rval)
    1618             : {
    1619           0 :     return CallObjFunc(MapObject::delete_, cx, obj, key, rval);
    1620             : }
    1621             : 
    1622             : JS_PUBLIC_API(bool)
    1623           0 : JS::MapClear(JSContext* cx, HandleObject obj)
    1624             : {
    1625           0 :     return CallObjFunc(&MapObject::clear, cx, obj);
    1626             : }
    1627             : 
    1628             : JS_PUBLIC_API(bool)
    1629           0 : JS::MapKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
    1630             : {
    1631           0 :     return CallObjFunc(&MapObject::iterator, cx, MapObject::Keys, obj, rval);
    1632             : }
    1633             : 
    1634             : JS_PUBLIC_API(bool)
    1635           0 : JS::MapValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
    1636             : {
    1637           0 :     return CallObjFunc(&MapObject::iterator, cx, MapObject::Values, obj, rval);
    1638             : }
    1639             : 
    1640             : JS_PUBLIC_API(bool)
    1641           0 : JS::MapEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
    1642             : {
    1643           0 :     return CallObjFunc(&MapObject::iterator, cx, MapObject::Entries, obj, rval);
    1644             : }
    1645             : 
    1646             : JS_PUBLIC_API(bool)
    1647           0 : JS::MapForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
    1648             : {
    1649           0 :     return forEach("MapForEach", cx, obj, callbackFn, thisVal);
    1650             : }
    1651             : 
    1652             : JS_PUBLIC_API(JSObject *)
    1653           0 : JS::NewSetObject(JSContext *cx)
    1654             : {
    1655           0 :     return SetObject::create(cx);
    1656             : }
    1657             : 
    1658             : JS_PUBLIC_API(uint32_t)
    1659           0 : JS::SetSize(JSContext *cx, HandleObject obj)
    1660             : {
    1661           0 :     return CallObjFunc<uint32_t>(&SetObject::size, cx, obj);
    1662             : }
    1663             : 
    1664             : JS_PUBLIC_API(bool)
    1665           0 : JS::SetAdd(JSContext *cx, HandleObject obj, HandleValue key)
    1666             : {
    1667           0 :     CHECK_REQUEST(cx);
    1668           0 :     assertSameCompartment(cx, obj, key);
    1669             : 
    1670             :     // Unwrap the object, and enter its compartment. If object isn't wrapped,
    1671             :     // this is essentially a noop.
    1672           0 :     RootedObject unwrappedObj(cx);
    1673           0 :     unwrappedObj = UncheckedUnwrap(obj);
    1674             :     {
    1675           0 :         JSAutoCompartment ac(cx, unwrappedObj);
    1676             : 
    1677             :         // If we passed in a wrapper, wrap key before adding to the set
    1678           0 :         RootedValue wrappedKey(cx, key);
    1679           0 :         if (obj != unwrappedObj) {
    1680           0 :             if (!JS_WrapValue(cx, &wrappedKey))
    1681           0 :                 return false;
    1682             :         }
    1683           0 :         return SetObject::add(cx, unwrappedObj, wrappedKey);
    1684             :     }
    1685             : }
    1686             : 
    1687             : JS_PUBLIC_API(bool)
    1688           0 : JS::SetHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
    1689             : {
    1690           0 :     return CallObjFunc(SetObject::has, cx, obj, key, rval);
    1691             : }
    1692             : 
    1693             : JS_PUBLIC_API(bool)
    1694           0 : JS::SetDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
    1695             : {
    1696           0 :     return CallObjFunc(SetObject::delete_, cx, obj, key, rval);
    1697             : }
    1698             : 
    1699             : JS_PUBLIC_API(bool)
    1700           0 : JS::SetClear(JSContext* cx, HandleObject obj)
    1701             : {
    1702           0 :     return CallObjFunc(&SetObject::clear, cx, obj);
    1703             : }
    1704             : 
    1705             : JS_PUBLIC_API(bool)
    1706           0 : JS::SetKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
    1707             : {
    1708           0 :     return SetValues(cx, obj, rval);
    1709             : }
    1710             : 
    1711             : JS_PUBLIC_API(bool)
    1712           0 : JS::SetValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
    1713             : {
    1714           0 :     return CallObjFunc(&SetObject::iterator, cx, SetObject::Values, obj, rval);
    1715             : }
    1716             : 
    1717             : JS_PUBLIC_API(bool)
    1718           0 : JS::SetEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
    1719             : {
    1720           0 :     return CallObjFunc(&SetObject::iterator, cx, SetObject::Entries, obj, rval);
    1721             : }
    1722             : 
    1723             : JS_PUBLIC_API(bool)
    1724           0 : JS::SetForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
    1725             : {
    1726           0 :     return forEach("SetForEach", cx, obj, callbackFn, thisVal);
    1727             : }

Generated by: LCOV version 1.13