Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
3
* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "builtin/WeakSetObject.h"
8
9
#include "jsapi.h"
10
11
#include "builtin/MapObject.h"
12
#include "js/PropertySpec.h"
13
#include "vm/GlobalObject.h"
14
#include "vm/Iteration.h"
15
#include "vm/JSContext.h"
16
#include "vm/SelfHosting.h"
17
18
#include "builtin/WeakMapObject-inl.h"
19
#include "vm/Interpreter-inl.h"
20
#include "vm/JSObject-inl.h"
21
#include "vm/NativeObject-inl.h"
22
23
using namespace js;
24
25
/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::is(HandleValue v) {
26
return v.isObject() && v.toObject().is<WeakSetObject>();
27
}
28
29
// ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296
30
// 23.4.3.1 WeakSet.prototype.add ( value )
31
/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::add_impl(
32
JSContext* cx, const CallArgs& args) {
33
MOZ_ASSERT(is(args.thisv()));
34
35
// Step 4.
36
if (!args.get(0).isObject()) {
37
ReportNotObject(cx, JSMSG_OBJECT_REQUIRED_WEAKSET_VAL, args.get(0));
38
return false;
39
}
40
41
// Steps 5-7.
42
RootedObject value(cx, &args[0].toObject());
43
Rooted<WeakSetObject*> map(cx, &args.thisv().toObject().as<WeakSetObject>());
44
if (!WeakCollectionPutEntryInternal(cx, map, value, TrueHandleValue)) {
45
return false;
46
}
47
48
// Steps 6.a.i, 8.
49
args.rval().set(args.thisv());
50
return true;
51
}
52
53
/* static */
54
bool WeakSetObject::add(JSContext* cx, unsigned argc, Value* vp) {
55
// Steps 1-3.
56
CallArgs args = CallArgsFromVp(argc, vp);
57
return CallNonGenericMethod<WeakSetObject::is, WeakSetObject::add_impl>(cx,
58
args);
59
}
60
61
// ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296
62
// 23.4.3.3 WeakSet.prototype.delete ( value )
63
/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::delete_impl(
64
JSContext* cx, const CallArgs& args) {
65
MOZ_ASSERT(is(args.thisv()));
66
67
// Step 4.
68
if (!args.get(0).isObject()) {
69
args.rval().setBoolean(false);
70
return true;
71
}
72
73
// Steps 5-6.
74
if (ObjectValueWeakMap* map =
75
args.thisv().toObject().as<WeakSetObject>().getMap()) {
76
JSObject* value = &args[0].toObject();
77
if (ObjectValueWeakMap::Ptr ptr = map->lookup(value)) {
78
map->remove(ptr);
79
args.rval().setBoolean(true);
80
return true;
81
}
82
}
83
84
// Step 7.
85
args.rval().setBoolean(false);
86
return true;
87
}
88
89
/* static */
90
bool WeakSetObject::delete_(JSContext* cx, unsigned argc, Value* vp) {
91
// Steps 1-3.
92
CallArgs args = CallArgsFromVp(argc, vp);
93
return CallNonGenericMethod<WeakSetObject::is, WeakSetObject::delete_impl>(
94
cx, args);
95
}
96
97
// ES2018 draft rev 7a2d3f053ecc2336fc19f377c55d52d78b11b296
98
// 23.4.3.4 WeakSet.prototype.has ( value )
99
/* static */ MOZ_ALWAYS_INLINE bool WeakSetObject::has_impl(
100
JSContext* cx, const CallArgs& args) {
101
MOZ_ASSERT(is(args.thisv()));
102
103
// Step 5.
104
if (!args.get(0).isObject()) {
105
args.rval().setBoolean(false);
106
return true;
107
}
108
109
// Steps 4, 6.
110
if (ObjectValueWeakMap* map =
111
args.thisv().toObject().as<WeakSetObject>().getMap()) {
112
JSObject* value = &args[0].toObject();
113
if (map->has(value)) {
114
args.rval().setBoolean(true);
115
return true;
116
}
117
}
118
119
// Step 7.
120
args.rval().setBoolean(false);
121
return true;
122
}
123
124
/* static */
125
bool WeakSetObject::has(JSContext* cx, unsigned argc, Value* vp) {
126
// Steps 1-3.
127
CallArgs args = CallArgsFromVp(argc, vp);
128
return CallNonGenericMethod<WeakSetObject::is, WeakSetObject::has_impl>(cx,
129
args);
130
}
131
132
const ClassSpec WeakSetObject::classSpec_ = {
133
GenericCreateConstructor<WeakSetObject::construct, 0,
134
gc::AllocKind::FUNCTION>,
135
GenericCreatePrototype<WeakSetObject>,
136
nullptr,
137
nullptr,
138
WeakSetObject::methods,
139
WeakSetObject::properties,
140
};
141
142
const JSClass WeakSetObject::class_ = {
143
"WeakSet",
144
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
145
JSCLASS_BACKGROUND_FINALIZE,
146
&WeakCollectionObject::classOps_, &WeakSetObject::classSpec_};
147
148
const JSClass WeakSetObject::protoClass_ = {
149
js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet), JS_NULL_CLASS_OPS,
150
&WeakSetObject::classSpec_};
151
152
const JSPropertySpec WeakSetObject::properties[] = {
153
JS_STRING_SYM_PS(toStringTag, "WeakSet", JSPROP_READONLY), JS_PS_END};
154
155
const JSFunctionSpec WeakSetObject::methods[] = {
156
JS_FN("add", add, 1, 0), JS_FN("delete", delete_, 1, 0),
157
JS_FN("has", has, 1, 0), JS_FS_END};
158
159
WeakSetObject* WeakSetObject::create(JSContext* cx,
160
HandleObject proto /* = nullptr */) {
161
return NewObjectWithClassProto<WeakSetObject>(cx, proto);
162
}
163
164
bool WeakSetObject::isBuiltinAdd(HandleValue add) {
165
return IsNativeFunction(add, WeakSetObject::add);
166
}
167
168
bool WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) {
169
// Based on our "Set" implementation instead of the more general ES6 steps.
170
CallArgs args = CallArgsFromVp(argc, vp);
171
172
if (!ThrowIfNotConstructing(cx, args, "WeakSet")) {
173
return false;
174
}
175
176
RootedObject proto(cx);
177
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakSet, &proto)) {
178
return false;
179
}
180
181
Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx, proto));
182
if (!obj) {
183
return false;
184
}
185
186
if (!args.get(0).isNullOrUndefined()) {
187
RootedValue iterable(cx, args[0]);
188
bool optimized = false;
189
if (!IsOptimizableInitForSet<GlobalObject::getOrCreateWeakSetPrototype,
190
isBuiltinAdd>(cx, obj, iterable, &optimized)) {
191
return false;
192
}
193
194
if (optimized) {
195
RootedValue keyVal(cx);
196
RootedObject keyObject(cx);
197
RootedArrayObject array(cx, &iterable.toObject().as<ArrayObject>());
198
for (uint32_t index = 0; index < array->getDenseInitializedLength();
199
++index) {
200
keyVal.set(array->getDenseElement(index));
201
MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
202
203
if (keyVal.isPrimitive()) {
204
ReportNotObject(cx, JSMSG_OBJECT_REQUIRED_WEAKSET_VAL, keyVal);
205
return false;
206
}
207
208
keyObject = &keyVal.toObject();
209
if (!WeakCollectionPutEntryInternal(cx, obj, keyObject,
210
TrueHandleValue)) {
211
return false;
212
}
213
}
214
} else {
215
FixedInvokeArgs<1> args2(cx);
216
args2[0].set(args[0]);
217
218
RootedValue thisv(cx, ObjectValue(*obj));
219
if (!CallSelfHostedFunction(cx, cx->names().WeakSetConstructorInit, thisv,
220
args2, args2.rval())) {
221
return false;
222
}
223
}
224
}
225
226
args.rval().setObject(*obj);
227
return true;
228
}
229
230
JS_FRIEND_API bool JS_NondeterministicGetWeakSetKeys(JSContext* cx,
231
HandleObject objArg,
232
MutableHandleObject ret) {
233
RootedObject obj(cx, UncheckedUnwrap(objArg));
234
if (!obj || !obj->is<WeakSetObject>()) {
235
ret.set(nullptr);
236
return true;
237
}
238
return WeakCollectionObject::nondeterministicGetKeys(
239
cx, obj.as<WeakCollectionObject>(), ret);
240
}