Bug 1874684 - Part 21: Rename SecondsAndNanoseconds::toTotalNanoseconds. r=dminor
[gecko.git] / js / src / builtin / WeakSetObject.cpp
blob3705e942182d3ae44a531ee924236b44b60e5ff5
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"
20 using namespace js;
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()));
32 // Step 4.
33 if (!CanBeHeldWeakly(cx, args.get(0))) {
34 unsigned errorNum = GetErrorNumber(false);
35 ReportValueError(cx, errorNum, JSDVG_IGNORE_STACK, args.get(0), nullptr);
36 return false;
39 // Steps 5-7.
40 RootedValue value(cx, args[0]);
41 Rooted<WeakSetObject*> map(cx, &args.thisv().toObject().as<WeakSetObject>());
42 if (!WeakCollectionPutEntryInternal(cx, map, value, TrueHandleValue)) {
43 return false;
46 // Steps 6.a.i, 8.
47 args.rval().set(args.thisv());
48 return true;
51 /* static */
52 bool WeakSetObject::add(JSContext* cx, unsigned argc, Value* vp) {
53 // Steps 1-3.
54 CallArgs args = CallArgsFromVp(argc, vp);
55 return CallNonGenericMethod<WeakSetObject::is, WeakSetObject::add_impl>(cx,
56 args);
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()));
65 // Step 4.
66 if (!CanBeHeldWeakly(cx, args.get(0))) {
67 args.rval().setBoolean(false);
68 return true;
71 // Steps 5-6.
72 if (ValueValueWeakMap* map =
73 args.thisv().toObject().as<WeakSetObject>().getMap()) {
74 Value value = args[0];
75 if (ValueValueWeakMap::Ptr ptr = map->lookup(value)) {
76 map->remove(ptr);
77 args.rval().setBoolean(true);
78 return true;
82 // Step 7.
83 args.rval().setBoolean(false);
84 return true;
87 /* static */
88 bool WeakSetObject::delete_(JSContext* cx, unsigned argc, Value* vp) {
89 // Steps 1-3.
90 CallArgs args = CallArgsFromVp(argc, vp);
91 return CallNonGenericMethod<WeakSetObject::is, WeakSetObject::delete_impl>(
92 cx, args);
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()));
101 // Step 5.
102 if (!CanBeHeldWeakly(cx, args.get(0))) {
103 args.rval().setBoolean(false);
104 return true;
107 // Steps 4, 6.
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);
113 return true;
117 // Step 7.
118 args.rval().setBoolean(false);
119 return true;
122 /* static */
123 bool WeakSetObject::has(JSContext* cx, unsigned argc, Value* vp) {
124 // Steps 1-3.
125 CallArgs args = CallArgsFromVp(argc, vp);
126 return CallNonGenericMethod<WeakSetObject::is, WeakSetObject::has_impl>(cx,
127 args);
130 const ClassSpec WeakSetObject::classSpec_ = {
131 GenericCreateConstructor<WeakSetObject::construct, 0,
132 gc::AllocKind::FUNCTION>,
133 GenericCreatePrototype<WeakSetObject>,
134 nullptr,
135 nullptr,
136 WeakSetObject::methods,
137 WeakSetObject::properties,
140 const JSClass WeakSetObject::class_ = {
141 "WeakSet",
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")) {
171 return false;
174 RootedObject proto(cx);
175 if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakSet, &proto)) {
176 return false;
179 Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx, proto));
180 if (!obj) {
181 return false;
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)) {
189 return false;
192 if (optimized) {
193 RootedValue keyVal(cx);
194 Rooted<ArrayObject*> array(cx, &iterable.toObject().as<ArrayObject>());
195 for (uint32_t index = 0; index < array->getDenseInitializedLength();
196 ++index) {
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),
203 nullptr);
204 return false;
207 if (!WeakCollectionPutEntryInternal(cx, obj, keyVal, TrueHandleValue)) {
208 return false;
211 } else {
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())) {
218 return false;
223 args.rval().setObject(*obj);
224 return true;
227 JS_PUBLIC_API bool JS_NondeterministicGetWeakSetKeys(JSContext* cx,
228 HandleObject objArg,
229 MutableHandleObject ret) {
230 RootedObject obj(cx, UncheckedUnwrap(objArg));
231 if (!obj || !obj->is<WeakSetObject>()) {
232 ret.set(nullptr);
233 return true;
235 return WeakCollectionObject::nondeterministicGetKeys(
236 cx, obj.as<WeakCollectionObject>(), ret);