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/WeakSetObject.h"
8 :
9 : #include "jsapi.h"
10 : #include "jscntxt.h"
11 : #include "jsiter.h"
12 :
13 : #include "builtin/MapObject.h"
14 : #include "builtin/SelfHostingDefines.h"
15 : #include "builtin/WeakMapObject.h"
16 : #include "vm/GlobalObject.h"
17 : #include "vm/SelfHosting.h"
18 :
19 : #include "jsobjinlines.h"
20 :
21 : #include "vm/Interpreter-inl.h"
22 : #include "vm/NativeObject-inl.h"
23 :
24 : using namespace js;
25 :
26 : const Class WeakSetObject::class_ = {
27 : "WeakSet",
28 : JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
29 : JSCLASS_HAS_RESERVED_SLOTS(WeakSetObject::RESERVED_SLOTS)
30 : };
31 :
32 : const JSPropertySpec WeakSetObject::properties[] = {
33 : JS_PS_END
34 : };
35 :
36 : const JSFunctionSpec WeakSetObject::methods[] = {
37 : JS_SELF_HOSTED_FN("add", "WeakSet_add", 1, 0),
38 : JS_SELF_HOSTED_FN("delete", "WeakSet_delete", 1, 0),
39 : JS_SELF_HOSTED_FN("has", "WeakSet_has", 1, 0),
40 : JS_FS_END
41 : };
42 :
43 : JSObject*
44 8 : WeakSetObject::initClass(JSContext* cx, HandleObject obj)
45 : {
46 8 : Handle<GlobalObject*> global = obj.as<GlobalObject>();
47 16 : RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
48 8 : if (!proto)
49 0 : return nullptr;
50 :
51 16 : Rooted<JSFunction*> ctor(cx, GlobalObject::createConstructor(cx, construct,
52 32 : ClassName(JSProto_WeakSet, cx), 0));
53 32 : if (!ctor ||
54 24 : !LinkConstructorAndPrototype(cx, ctor, proto) ||
55 48 : !DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
56 64 : !DefineToStringTag(cx, proto, cx->names().WeakSet) ||
57 32 : !GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakSet, ctor, proto))
58 : {
59 0 : return nullptr;
60 : }
61 8 : return proto;
62 : }
63 :
64 : WeakSetObject*
65 3 : WeakSetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
66 : {
67 6 : RootedObject map(cx, NewBuiltinClassInstance<WeakMapObject>(cx));
68 3 : if (!map)
69 0 : return nullptr;
70 :
71 3 : WeakSetObject* obj = NewObjectWithClassProto<WeakSetObject>(cx, proto);
72 3 : if (!obj)
73 0 : return nullptr;
74 :
75 3 : obj->setReservedSlot(WEAKSET_MAP_SLOT, ObjectValue(*map));
76 3 : return obj;
77 : }
78 :
79 : bool
80 0 : WeakSetObject::isBuiltinAdd(HandleValue add, JSContext* cx)
81 : {
82 : JSFunction* addFn;
83 0 : return IsFunctionObject(add, &addFn) && IsSelfHostedFunctionWithName(addFn, cx->names().WeakSet_add);
84 : }
85 :
86 : bool
87 3 : WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
88 : {
89 : // Based on our "Set" implementation instead of the more general ES6 steps.
90 3 : CallArgs args = CallArgsFromVp(argc, vp);
91 :
92 3 : if (!ThrowIfNotConstructing(cx, args, "WeakSet"))
93 0 : return false;
94 :
95 6 : RootedObject proto(cx);
96 3 : if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
97 0 : return false;
98 :
99 6 : Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx, proto));
100 3 : if (!obj)
101 0 : return false;
102 :
103 3 : if (!args.get(0).isNullOrUndefined()) {
104 0 : RootedValue iterable(cx, args[0]);
105 0 : bool optimized = false;
106 0 : if (!IsOptimizableInitForSet<GlobalObject::getOrCreateWeakSetPrototype, isBuiltinAdd>(cx, obj, iterable, &optimized))
107 0 : return false;
108 :
109 0 : if (optimized) {
110 0 : RootedValue keyVal(cx);
111 0 : RootedObject keyObject(cx);
112 0 : RootedValue placeholder(cx, BooleanValue(true));
113 0 : RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
114 0 : RootedArrayObject array(cx, &iterable.toObject().as<ArrayObject>());
115 0 : for (uint32_t index = 0; index < array->getDenseInitializedLength(); ++index) {
116 0 : keyVal.set(array->getDenseElement(index));
117 0 : MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
118 :
119 0 : if (keyVal.isPrimitive()) {
120 0 : ReportNotObjectWithName(cx, "WeakSet value", keyVal);
121 0 : return false;
122 : }
123 :
124 0 : keyObject = &keyVal.toObject();
125 0 : if (!SetWeakMapEntry(cx, map, keyObject, placeholder))
126 0 : return false;
127 : }
128 : } else {
129 0 : FixedInvokeArgs<1> args2(cx);
130 0 : args2[0].set(args[0]);
131 :
132 0 : RootedValue thisv(cx, ObjectValue(*obj));
133 0 : if (!CallSelfHostedFunction(cx, cx->names().WeakSetConstructorInit, thisv, args2, args2.rval()))
134 0 : return false;
135 : }
136 : }
137 :
138 3 : args.rval().setObject(*obj);
139 3 : return true;
140 : }
141 :
142 :
143 : JSObject*
144 8 : js::InitWeakSetClass(JSContext* cx, HandleObject obj)
145 : {
146 8 : return WeakSetObject::initClass(cx, obj);
147 : }
148 :
149 : JS_FRIEND_API(bool)
150 0 : JS_NondeterministicGetWeakSetKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
151 : {
152 0 : RootedObject obj(cx, objArg);
153 0 : obj = UncheckedUnwrap(obj);
154 0 : if (!obj || !obj->is<WeakSetObject>()) {
155 0 : ret.set(nullptr);
156 0 : return true;
157 : }
158 :
159 0 : Rooted<WeakSetObject*> weakset(cx, &obj->as<WeakSetObject>());
160 0 : if (!weakset)
161 0 : return false;
162 :
163 0 : RootedObject map(cx, &weakset->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
164 0 : return JS_NondeterministicGetWeakMapKeys(cx, map, ret);
165 9 : }
|