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
qv4mapobject.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
7#include "qv4estable_p.h"
8#include "qv4symbol_p.h"
9
10using namespace QV4;
11
15
16void Heap::WeakMapCtor::init(QV4::ExecutionEngine *engine)
17{
18 Heap::FunctionObject::init(engine, QStringLiteral("WeakMap"));
19}
20
21void Heap::MapCtor::init(QV4::ExecutionEngine *engine)
22{
23 Heap::FunctionObject::init(engine, QStringLiteral("Map"));
24}
25
26ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool weakMap)
27{
28 Scope scope(f);
29 Scoped<MapObject> a(scope, scope.engine->memoryManager->allocate<MapObject>());
30 bool protoSet = false;
31 if (newTarget)
32 protoSet = a->setProtoFromNewTarget(newTarget);
33 if (!protoSet && weakMap) {
34 a->setPrototypeOf(scope.engine->weakMapPrototype());
35 scope.engine->memoryManager->registerWeakMap(a->d());
36 }
37 a->d()->isWeakMap = weakMap;
38
39 if (argc > 0) {
40 ScopedValue iterable(scope, argv[0]);
41
42 if (!iterable->isNullOrUndefined()) {
43 ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(QString::fromLatin1("set")))));
44 if (!adder)
45 return scope.engine->throwTypeError();
46
47 ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true));
48 if (scope.hasException())
49 return Encode::undefined();
50 Q_ASSERT(iter);
51
52 ScopedValue obj(scope);
53 Value *arguments = scope.constructUndefined(2);
54 ScopedValue done(scope);
55 forever {
56 done = Runtime::IteratorNext::call(scope.engine, iter, obj);
57 if (scope.hasException())
58 break;
59 if (done->toBoolean())
60 return a->asReturnedValue();
61 const Object *o = obj->objectValue();
62 if (!o) {
63 scope.engine->throwTypeError();
64 break;
65 }
66
67 arguments[0] = o->get(PropertyKey::fromArrayIndex(0));
68 if (scope.hasException())
69 break;
70 arguments[1] = o->get(PropertyKey::fromArrayIndex(1));
71 if (scope.hasException())
72 break;
73
74 adder->call(a, arguments, 2);
75 if (scope.hasException())
76 break;
77 }
78 return Runtime::IteratorClose::call(scope.engine, iter);
79 }
80 }
81 return a->asReturnedValue();
82
83}
84
85ReturnedValue WeakMapCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
86{
87 return construct(f, argv, argc, newTarget, true);
88}
89
90ReturnedValue WeakMapCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
91{
92 Scope scope(f);
93 return scope.engine->throwTypeError(QString::fromLatin1("(Weak)Map requires new"));
94}
95
96
97ReturnedValue MapCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
98{
99 return construct(f, argv, argc, newTarget, false);
100}
101
102void WeakMapPrototype::init(ExecutionEngine *engine, Object *ctor)
103{
104 Scope scope(engine);
105 ScopedObject o(scope);
106 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
107 ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
108 defineDefaultProperty(engine->id_constructor(), (o = ctor));
109
110 defineDefaultProperty(QStringLiteral("delete"), method_delete, 1);
111 defineDefaultProperty(QStringLiteral("get"), method_get, 1);
112 defineDefaultProperty(QStringLiteral("has"), method_has, 1);
113 defineDefaultProperty(QStringLiteral("set"), method_set, 2);
114
115 ScopedString val(scope, engine->newString(QLatin1String("WeakMap")));
116 defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
117}
118
119
120void MapPrototype::init(ExecutionEngine *engine, Object *ctor)
121{
122 Scope scope(engine);
123 ScopedObject o(scope);
124 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
125 ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
126 ctor->addSymbolSpecies();
127 defineDefaultProperty(engine->id_constructor(), (o = ctor));
128
129 defineDefaultProperty(QStringLiteral("clear"), method_clear, 0);
130 defineDefaultProperty(QStringLiteral("delete"), method_delete, 1);
131 defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
132 defineDefaultProperty(QStringLiteral("get"), method_get, 1);
133 defineDefaultProperty(QStringLiteral("has"), method_has, 1);
134 defineDefaultProperty(QStringLiteral("keys"), method_keys, 0);
135 defineDefaultProperty(QStringLiteral("set"), method_set, 2);
136 defineAccessorProperty(QStringLiteral("size"), method_get_size, nullptr);
137 defineDefaultProperty(QStringLiteral("values"), method_values, 0);
138
139 // Per the spec, the value for entries/@@iterator is the same
140 ScopedString valString(scope, scope.engine->newIdentifier(QStringLiteral("entries")));
141 ScopedFunctionObject entriesFn(scope, FunctionObject::createBuiltinFunction(engine, valString, MapPrototype::method_entries, 0));
142 defineDefaultProperty(QStringLiteral("entries"), entriesFn);
143 defineDefaultProperty(engine->symbol_iterator(), entriesFn);
144
145 ScopedString val(scope, engine->newString(QLatin1String("Map")));
146 defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
147}
148
149void Heap::MapObject::init()
150{
151 Object::init();
152 esTable = new ESTable();
153}
154
155void Heap::MapObject::destroy()
156{
157 delete esTable;
158 esTable = nullptr;
159}
160
161void Heap::MapObject::removeUnmarkedKeys()
162{
163 esTable->removeUnmarkedKeys();
164}
165
166void Heap::MapObject::markObjects(Heap::Base *that, MarkStack *markStack)
167{
168 MapObject *m = static_cast<MapObject *>(that);
169 m->esTable->markObjects(markStack, m->isWeakMap);
170 Object::markObjects(that, markStack);
171}
172
173ReturnedValue WeakMapPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
174{
175 Scope scope(b);
176 Scoped<MapObject> that(scope, thisObject);
177 if (!that || !that->d()->isWeakMap)
178 return scope.engine->throwTypeError();
179 if (!argc || !argv[0].isObject())
180 return Encode(false);
181
182 return Encode(that->d()->esTable->remove(argv[0]));
183
184}
185
186ReturnedValue WeakMapPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
187{
188 Scope scope(b);
189 Scoped<MapObject> that(scope, thisObject);
190 if (!that || !that->d()->isWeakMap)
191 return scope.engine->throwTypeError();
192 if (!argc || !argv[0].isObject())
193 return Encode::undefined();
194
195 return that->d()->esTable->get(argv[0]);
196}
197
198ReturnedValue WeakMapPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
199{
200 Scope scope(b);
201 Scoped<MapObject> that(scope, thisObject);
202 if (!that || !that->d()->isWeakMap)
203 return scope.engine->throwTypeError();
204 if (!argc || !argv[0].isObject())
205 return Encode(false);
206
207 return Encode(that->d()->esTable->has(argv[0]));
208}
209
210ReturnedValue WeakMapPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
211{
212 Scope scope(b);
213 Scoped<MapObject> that(scope, thisObject);
214 if ((!that || !that->d()->isWeakMap) ||
215 (!argc || !argv[0].isObject()))
216 return scope.engine->throwTypeError();
217
218 QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
219 if (scope.engine->memoryManager->gcStateMachine->state <= GCState::FreeWeakMaps)
220 return;
221 Q_ASSERT(argv[0].heapObject());
222 argv[0].heapObject()->mark(ms);
223 if (argc > 1) {
224 if (auto *h = argv[1].heapObject())
225 h->mark(ms);
226 }
227 });
228
229 that->d()->esTable->set(argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
230 return that.asReturnedValue();
231}
232
233
234ReturnedValue MapPrototype::method_clear(const FunctionObject *b, const Value *thisObject, const Value *, int)
235{
236 Scope scope(b);
237 Scoped<MapObject> that(scope, thisObject);
238 if (!that || that->d()->isWeakMap)
239 return scope.engine->throwTypeError();
240
241 that->d()->esTable->clear();
242 return Encode::undefined();
243}
244
245ReturnedValue MapPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
246{
247 Scope scope(b);
248 Scoped<MapObject> that(scope, thisObject);
249 if (!that || that->d()->isWeakMap)
250 return scope.engine->throwTypeError();
251
252 return Encode(that->d()->esTable->remove(argc ? argv[0] : Value::undefinedValue()));
253}
254
255ReturnedValue MapPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
256{
257 Scope scope(b);
258 Scoped<MapObject> that(scope, thisObject);
259 if (!that || that->d()->isWeakMap)
260 return scope.engine->throwTypeError();
261
262 Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that));
263 ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
264 return ao->asReturnedValue();
265}
266
267ReturnedValue MapPrototype::method_forEach(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
268{
269 Scope scope(b);
270 Scoped<MapObject> that(scope, thisObject);
271 if (!that || that->d()->isWeakMap)
272 return scope.engine->throwTypeError();
273
274 ScopedFunctionObject callbackfn(scope, argv[0]);
275 if (!callbackfn)
276 return scope.engine->throwTypeError();
277
278 ScopedValue thisArg(scope, Value::undefinedValue());
279 if (argc > 1)
280 thisArg = ScopedValue(scope, argv[1]);
281
282 Value *arguments = scope.constructUndefined(3);
283 arguments[2] = that;
284
285 ESTable::ShiftObserver observer{};
286 that->d()->esTable->observeShifts(observer);
287
288 while (observer.pivot < that->d()->esTable->size()) {
289 that->d()->esTable->iterate(observer.pivot, &arguments[1], &arguments[0]); // fill in key (0), value (1)
290
291 callbackfn->call(thisArg, arguments, 3);
293
294 observer.next();
295 }
296
297 that->d()->esTable->stopObservingShifts(observer);
298
299 return Encode::undefined();
300}
301
302ReturnedValue MapPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
303{
304 Scope scope(b);
305 Scoped<MapObject> that(scope, thisObject);
306 if (!that || that->d()->isWeakMap)
307 return scope.engine->throwTypeError();
308
309 return that->d()->esTable->get(argc ? argv[0] : Value::undefinedValue());
310}
311
312ReturnedValue MapPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
313{
314 Scope scope(b);
315 Scoped<MapObject> that(scope, thisObject);
316 if (!that || that->d()->isWeakMap)
317 return scope.engine->throwTypeError();
318
319 return Encode(that->d()->esTable->has(argc ? argv[0] : Value::undefinedValue()));
320}
321
322ReturnedValue MapPrototype::method_keys(const FunctionObject *b, const Value *thisObject, const Value *, int)
323{
324 Scope scope(b);
325 Scoped<MapObject> that(scope, thisObject);
326 if (!that || that->d()->isWeakMap)
327 return scope.engine->throwTypeError();
328
329 Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that));
330 ao->d()->iterationKind = IteratorKind::KeyIteratorKind;
331 return ao->asReturnedValue();
332}
333
334ReturnedValue MapPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
335{
336 Scope scope(b);
337 Scoped<MapObject> that(scope, thisObject);
338 if (!that || that->d()->isWeakMap)
339 return scope.engine->throwTypeError();
340
341 QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
342 if (auto *h = argv[0].heapObject())
343 h->mark(ms);
344 if (argc > 1) {
345 if (auto *h = argv[1].heapObject())
346 h->mark(ms);
347 }
348 });
349
350 that->d()->esTable->set(argc ? argv[0] : Value::undefinedValue(), argc > 1 ? argv[1] : Value::undefinedValue());
351 return that.asReturnedValue();
352}
353
354ReturnedValue MapPrototype::method_get_size(const FunctionObject *b, const Value *thisObject, const Value *, int)
355{
356 Scope scope(b);
357 Scoped<MapObject> that(scope, thisObject);
358 if (!that || that->d()->isWeakMap)
359 return scope.engine->throwTypeError();
360
361 return Encode(that->d()->esTable->size());
362}
363
364ReturnedValue MapPrototype::method_values(const FunctionObject *b, const Value *thisObject, const Value *, int)
365{
366 Scope scope(b);
367 Scoped<MapObject> that(scope, thisObject);
368 if (!that || that->d()->isWeakMap)
369 return scope.engine->throwTypeError();
370
371 Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that));
372 ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
373 return ao->asReturnedValue();
374}
DEFINE_OBJECT_VTABLE(WeakMapCtor)
DEFINE_OBJECT_VTABLE(MapObject)
DEFINE_OBJECT_VTABLE(MapCtor)
#define CHECK_EXCEPTION()