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/. */
7 #include "builtin/WeakSetObject.h"
9 #include "builtin/MapObject.h"
10 #include "js/friend/ErrorMessages.h" // JSMSG_*
11 #include "js/PropertySpec.h"
12 #include "vm/GlobalObject.h"
13 #include "vm/JSContext.h"
14 #include "vm/SelfHosting.h"
16 #include "builtin/WeakMapObject-inl.h"
17 #include "vm/JSObject-inl.h"
18 #include "vm/NativeObject-inl.h"
22 /* static */ MOZ_ALWAYS_INLINE
bool WeakSetObject::is(HandleValue v
) {
23 return v
.isObject() && v
.toObject().is
<WeakSetObject
>();
26 // ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296
27 // 23.4.3.1 WeakSet.prototype.add ( value )
28 /* static */ MOZ_ALWAYS_INLINE
bool WeakSetObject::add_impl(
29 JSContext
* cx
, const CallArgs
& args
) {
30 MOZ_ASSERT(is(args
.thisv()));
33 if (!CanBeHeldWeakly(cx
, args
.get(0))) {
34 unsigned errorNum
= GetErrorNumber(false);
35 ReportValueError(cx
, errorNum
, JSDVG_IGNORE_STACK
, args
.get(0), nullptr);
40 RootedValue
value(cx
, args
[0]);
41 Rooted
<WeakSetObject
*> map(cx
, &args
.thisv().toObject().as
<WeakSetObject
>());
42 if (!WeakCollectionPutEntryInternal(cx
, map
, value
, TrueHandleValue
)) {
47 args
.rval().set(args
.thisv());
52 bool WeakSetObject::add(JSContext
* cx
, unsigned argc
, Value
* vp
) {
54 CallArgs args
= CallArgsFromVp(argc
, vp
);
55 return CallNonGenericMethod
<WeakSetObject::is
, WeakSetObject::add_impl
>(cx
,
59 // ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296
60 // 23.4.3.3 WeakSet.prototype.delete ( value )
61 /* static */ MOZ_ALWAYS_INLINE
bool WeakSetObject::delete_impl(
62 JSContext
* cx
, const CallArgs
& args
) {
63 MOZ_ASSERT(is(args
.thisv()));
66 if (!CanBeHeldWeakly(cx
, args
.get(0))) {
67 args
.rval().setBoolean(false);
72 if (ValueValueWeakMap
* map
=
73 args
.thisv().toObject().as
<WeakSetObject
>().getMap()) {
74 Value value
= args
[0];
75 if (ValueValueWeakMap::Ptr ptr
= map
->lookup(value
)) {
77 args
.rval().setBoolean(true);
83 args
.rval().setBoolean(false);
88 bool WeakSetObject::delete_(JSContext
* cx
, unsigned argc
, Value
* vp
) {
90 CallArgs args
= CallArgsFromVp(argc
, vp
);
91 return CallNonGenericMethod
<WeakSetObject::is
, WeakSetObject::delete_impl
>(
95 // ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296
96 // 23.4.3.4 WeakSet.prototype.has ( value )
97 /* static */ MOZ_ALWAYS_INLINE
bool WeakSetObject::has_impl(
98 JSContext
* cx
, const CallArgs
& args
) {
99 MOZ_ASSERT(is(args
.thisv()));
102 if (!CanBeHeldWeakly(cx
, args
.get(0))) {
103 args
.rval().setBoolean(false);
108 if (ValueValueWeakMap
* map
=
109 args
.thisv().toObject().as
<WeakSetObject
>().getMap()) {
110 Value value
= args
[0];
111 if (map
->has(value
)) {
112 args
.rval().setBoolean(true);
118 args
.rval().setBoolean(false);
123 bool WeakSetObject::has(JSContext
* cx
, unsigned argc
, Value
* vp
) {
125 CallArgs args
= CallArgsFromVp(argc
, vp
);
126 return CallNonGenericMethod
<WeakSetObject::is
, WeakSetObject::has_impl
>(cx
,
130 const ClassSpec
WeakSetObject::classSpec_
= {
131 GenericCreateConstructor
<WeakSetObject::construct
, 0,
132 gc::AllocKind::FUNCTION
>,
133 GenericCreatePrototype
<WeakSetObject
>,
136 WeakSetObject::methods
,
137 WeakSetObject::properties
,
140 const JSClass
WeakSetObject::class_
= {
142 JSCLASS_HAS_RESERVED_SLOTS(SlotCount
) |
143 JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet
) | JSCLASS_BACKGROUND_FINALIZE
,
144 &WeakCollectionObject::classOps_
, &WeakSetObject::classSpec_
};
146 const JSClass
WeakSetObject::protoClass_
= {
147 "WeakSet.prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet
),
148 JS_NULL_CLASS_OPS
, &WeakSetObject::classSpec_
};
150 const JSPropertySpec
WeakSetObject::properties
[] = {
151 JS_STRING_SYM_PS(toStringTag
, "WeakSet", JSPROP_READONLY
), JS_PS_END
};
153 const JSFunctionSpec
WeakSetObject::methods
[] = {
154 JS_FN("add", add
, 1, 0), JS_FN("delete", delete_
, 1, 0),
155 JS_FN("has", has
, 1, 0), JS_FS_END
};
157 WeakSetObject
* WeakSetObject::create(JSContext
* cx
,
158 HandleObject proto
/* = nullptr */) {
159 return NewObjectWithClassProto
<WeakSetObject
>(cx
, proto
);
162 bool WeakSetObject::isBuiltinAdd(HandleValue add
) {
163 return IsNativeFunction(add
, WeakSetObject::add
);
166 bool WeakSetObject::construct(JSContext
* cx
, unsigned argc
, Value
* vp
) {
167 // Based on our "Set" implementation instead of the more general ES6 steps.
168 CallArgs args
= CallArgsFromVp(argc
, vp
);
170 if (!ThrowIfNotConstructing(cx
, args
, "WeakSet")) {
174 RootedObject
proto(cx
);
175 if (!GetPrototypeFromBuiltinConstructor(cx
, args
, JSProto_WeakSet
, &proto
)) {
179 Rooted
<WeakSetObject
*> obj(cx
, WeakSetObject::create(cx
, proto
));
184 if (!args
.get(0).isNullOrUndefined()) {
185 RootedValue
iterable(cx
, args
[0]);
186 bool optimized
= false;
187 if (!IsOptimizableInitForSet
<GlobalObject::getOrCreateWeakSetPrototype
,
188 isBuiltinAdd
>(cx
, obj
, iterable
, &optimized
)) {
193 RootedValue
keyVal(cx
);
194 Rooted
<ArrayObject
*> array(cx
, &iterable
.toObject().as
<ArrayObject
>());
195 for (uint32_t index
= 0; index
< array
->getDenseInitializedLength();
197 keyVal
.set(array
->getDenseElement(index
));
198 MOZ_ASSERT(!keyVal
.isMagic(JS_ELEMENTS_HOLE
));
200 if (!CanBeHeldWeakly(cx
, keyVal
)) {
201 unsigned errorNum
= GetErrorNumber(false);
202 ReportValueError(cx
, errorNum
, JSDVG_IGNORE_STACK
, args
.get(0),
207 if (!WeakCollectionPutEntryInternal(cx
, obj
, keyVal
, TrueHandleValue
)) {
212 FixedInvokeArgs
<1> args2(cx
);
213 args2
[0].set(args
[0]);
215 RootedValue
thisv(cx
, ObjectValue(*obj
));
216 if (!CallSelfHostedFunction(cx
, cx
->names().WeakSetConstructorInit
, thisv
,
217 args2
, args2
.rval())) {
223 args
.rval().setObject(*obj
);
227 JS_PUBLIC_API
bool JS_NondeterministicGetWeakSetKeys(JSContext
* cx
,
229 MutableHandleObject ret
) {
230 RootedObject
obj(cx
, UncheckedUnwrap(objArg
));
231 if (!obj
|| !obj
->is
<WeakSetObject
>()) {
235 return WeakCollectionObject::nondeterministicGetKeys(
236 cx
, obj
.as
<WeakCollectionObject
>(), ret
);