Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4setobject.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 Crimson AS <info@crimson.no>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5
8#include "qv4estable_p.h"
9#include "qv4symbol_p.h"
10
11using namespace QV4;
12using namespace Qt::Literals::StringLiterals;
13
17
18void Heap::WeakSetCtor::init(QV4::ExecutionEngine *engine)
19{
20 Heap::FunctionObject::init(engine, QStringLiteral("WeakSet"));
21}
22
23void Heap::SetCtor::init(QV4::ExecutionEngine *engine)
24{
25 Heap::FunctionObject::init(engine, QStringLiteral("Set"));
26}
27
28ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool isWeak)
29{
30 Scope scope(f);
31 Scoped<SetObject> a(scope, scope.engine->memoryManager->allocate<SetObject>());
32 bool protoSet = false;
33 if (newTarget)
34 protoSet = a->setProtoFromNewTarget(newTarget);
35 if (!protoSet && isWeak)
36 a->setPrototypeOf(scope.engine->weakSetPrototype());
37 a->d()->isWeakSet = isWeak;
38
39 if (argc > 0) {
40 ScopedValue iterable(scope, argv[0]);
41 if (!iterable->isUndefined() && !iterable->isNull()) {
42 ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(u"add"_s))));
43 if (!adder)
44 return scope.engine->throwTypeError();
45 ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true));
47 if (!iter)
48 return a.asReturnedValue();
49
50 Value *nextValue = scope.constructUndefined(1);
51 ScopedValue done(scope);
52 forever {
53 done = Runtime::IteratorNext::call(scope.engine, iter, nextValue);
55 if (done->toBoolean())
56 return a.asReturnedValue();
57
58 adder->call(a, nextValue, 1);
59 if (scope.hasException())
60 return Runtime::IteratorClose::call(scope.engine, iter);
61 }
62 }
63 }
64
65 return a.asReturnedValue();
66}
67
68ReturnedValue WeakSetCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
69{
70 return construct(f, argv, argc, newTarget, true);
71}
72
73ReturnedValue WeakSetCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
74{
75 Scope scope(f);
76 return scope.engine->throwTypeError(QString::fromLatin1("Set requires new"));
77}
78
79ReturnedValue SetCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
80{
81 return construct(f, argv, argc, newTarget, false);
82}
83
84void WeakSetPrototype::init(ExecutionEngine *engine, Object *ctor)
85{
86 Scope scope(engine);
87 ScopedObject o(scope);
88 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
89 ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
90 defineDefaultProperty(engine->id_constructor(), (o = ctor));
91
92 defineDefaultProperty(QStringLiteral("add"), method_add, 1);
93 defineDefaultProperty(QStringLiteral("delete"), method_delete, 1);
94 defineDefaultProperty(QStringLiteral("has"), method_has, 1);
95
96 ScopedString val(scope, engine->newString(QLatin1String("WeakSet")));
97 defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
98}
99
100ReturnedValue WeakSetPrototype::method_add(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
101{
102 Scope scope(b);
103 Scoped<SetObject> that(scope, thisObject);
104 if ((!that || !that->d()->isWeakSet) ||
105 (!argc || !argv[0].isObject()))
106 return scope.engine->throwTypeError();
107
108 QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
109 if (scope.engine->memoryManager->gcStateMachine->state <= GCState::FreeWeakSets)
110 return;
111 argv[0].heapObject()->mark(ms);
112 });
113
114 that->d()->esTable->set(argv[0], Value::undefinedValue());
115 return that.asReturnedValue();
116}
117
118ReturnedValue WeakSetPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
119{
120 Scope scope(b);
121 Scoped<SetObject> that(scope, thisObject);
122 if (!that || !that->d()->isWeakSet)
123 return scope.engine->throwTypeError();
124 if (!argc || !argv[0].isObject())
125 return Encode(false);
126
127 return Encode(that->d()->esTable->remove(argv[0]));
128}
129
130ReturnedValue WeakSetPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
131{
132 Scope scope(b);
133 Scoped<SetObject> that(scope, thisObject);
134 if (!that || !that->d()->isWeakSet)
135 return scope.engine->throwTypeError();
136 if (!argc || !argv[0].isObject())
137 return Encode(false);
138
139 return Encode(that->d()->esTable->has(argv[0]));
140}
141
142void SetPrototype::init(ExecutionEngine *engine, Object *ctor)
143{
144 Scope scope(engine);
145 ScopedObject o(scope);
146 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
147 ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
148 ctor->addSymbolSpecies();
149 defineDefaultProperty(engine->id_constructor(), (o = ctor));
150
151 defineDefaultProperty(QStringLiteral("add"), method_add, 1);
152 defineDefaultProperty(QStringLiteral("clear"), method_clear, 0);
153 defineDefaultProperty(QStringLiteral("delete"), method_delete, 1);
154 defineDefaultProperty(QStringLiteral("entries"), method_entries, 0);
155 defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
156 defineDefaultProperty(QStringLiteral("has"), method_has, 1);
157 defineAccessorProperty(QStringLiteral("size"), method_get_size, nullptr);
158
159 // Per the spec, the value for 'keys' is the same as 'values'.
160 ScopedString valString(scope, scope.engine->newIdentifier(QStringLiteral("values")));
161 ScopedFunctionObject valuesFn(scope, FunctionObject::createBuiltinFunction(engine, valString, SetPrototype::method_values, 0));
162 defineDefaultProperty(QStringLiteral("keys"), valuesFn);
163 defineDefaultProperty(QStringLiteral("values"), valuesFn);
164
165 defineDefaultProperty(engine->symbol_iterator(), valuesFn);
166
167 ScopedString val(scope, engine->newString(QLatin1String("Set")));
168 defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
169}
170
171void Heap::SetObject::init()
172{
173 Object::init();
174 esTable = new ESTable();
175}
176
177void Heap::SetObject::destroy()
178{
179 delete esTable;
180 esTable = 0;
181}
182
183void Heap::SetObject::removeUnmarkedKeys()
184{
185 esTable->removeUnmarkedKeys();
186}
187
188void Heap::SetObject::markObjects(Heap::Base *that, MarkStack *markStack)
189{
190 SetObject *s = static_cast<SetObject *>(that);
191 s->esTable->markObjects(markStack, s->isWeakSet);
192 Object::markObjects(that, markStack);
193}
194
195ReturnedValue SetPrototype::method_add(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
196{
197 Scope scope(b);
198 Scoped<SetObject> that(scope, thisObject);
199 if (!that || that->d()->isWeakSet)
200 return scope.engine->throwTypeError();
201
202 QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
203 if (auto *h = argv[0].heapObject())
204 h->mark(ms);
205 });
206
207 that->d()->esTable->set(argv[0], Value::undefinedValue());
208 return that.asReturnedValue();
209}
210
211ReturnedValue SetPrototype::method_clear(const FunctionObject *b, const Value *thisObject, const Value *, int)
212{
213 Scope scope(b);
214 Scoped<SetObject> that(scope, thisObject);
215 if (!that || that->d()->isWeakSet)
216 return scope.engine->throwTypeError();
217
218 that->d()->esTable->clear();
219 return Encode::undefined();
220}
221
222ReturnedValue SetPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
223{
224 Scope scope(b);
225 Scoped<SetObject> that(scope, thisObject);
226 if (!that || that->d()->isWeakSet)
227 return scope.engine->throwTypeError();
228
229 return Encode(that->d()->esTable->remove(argv[0]));
230}
231
232ReturnedValue SetPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
233{
234 Scope scope(b);
235 Scoped<SetObject> that(scope, thisObject);
236 if (!that || that->d()->isWeakSet)
237 return scope.engine->throwTypeError();
238
239 Scoped<SetIteratorObject> ao(scope, scope.engine->newSetIteratorObject(that));
240 ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
241 return ao->asReturnedValue();
242}
243
244ReturnedValue SetPrototype::method_forEach(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
245{
246 Scope scope(b);
247 Scoped<SetObject> that(scope, thisObject);
248 if (!that || that->d()->isWeakSet)
249 return scope.engine->throwTypeError();
250
251 ScopedFunctionObject callbackfn(scope, argv[0]);
252 if (!callbackfn)
253 return scope.engine->throwTypeError();
254
255 ScopedValue thisArg(scope, Value::undefinedValue());
256 if (argc > 1)
257 thisArg = ScopedValue(scope, argv[1]);
258
259 ESTable::ShiftObserver observer{};
260 that->d()->esTable->observeShifts(observer);
261
262 Value *arguments = scope.constructUndefined(3);
263 while (observer.pivot < that->d()->esTable->size()) {
264 that->d()->esTable->iterate(observer.pivot, &arguments[0], &arguments[1]); // fill in key (0), value (1)
265 arguments[1] = arguments[0]; // but for set, we want to return the key twice; value is always undefined.
266
267 arguments[2] = that;
268 callbackfn->call(thisArg, arguments, 3);
270
271 observer.next();
272 }
273
274 that->d()->esTable->stopObservingShifts(observer);
275
276 return Encode::undefined();
277}
278
279ReturnedValue SetPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
280{
281 Scope scope(b);
282 Scoped<SetObject> that(scope, thisObject);
283 if (!that || that->d()->isWeakSet)
284 return scope.engine->throwTypeError();
285
286 return Encode(that->d()->esTable->has(argv[0]));
287}
288
289ReturnedValue SetPrototype::method_get_size(const FunctionObject *b, const Value *thisObject, const Value *, int)
290{
291 Scope scope(b);
292 Scoped<SetObject> that(scope, thisObject);
293 if (!that || that->d()->isWeakSet)
294 return scope.engine->throwTypeError();
295
296 return Encode(that->d()->esTable->size());
297}
298
299ReturnedValue SetPrototype::method_values(const FunctionObject *b, const Value *thisObject, const Value *, int)
300{
301 Scope scope(b);
302 Scoped<SetObject> that(scope, thisObject);
303 if (!that || that->d()->isWeakSet)
304 return scope.engine->throwTypeError();
305
306 Scoped<SetIteratorObject> ao(scope, scope.engine->newSetIteratorObject(that));
307 ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
308 return ao->asReturnedValue();
309}
#define CHECK_EXCEPTION()
DEFINE_OBJECT_VTABLE(WeakSetCtor)
DEFINE_OBJECT_VTABLE(SetCtor)
DEFINE_OBJECT_VTABLE(SetObject)