Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4typedarray.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4typedarray_p.h"
6#include "qv4arraybuffer_p.h"
7#include "qv4symbol_p.h"
8#include "qv4runtime_p.h"
9#include <QtCore/qatomic.h>
10
11#include <cmath>
12
13using namespace QV4;
14
20
22
23static inline int toInt32(Value v)
24{
25 Q_ASSERT(v.isNumber());
26 if (v.isInteger())
27 return v.integerValue();
28 return QJSNumberCoercion::toInteger(v.doubleValue());
29}
30
31static inline double toDouble(Value v)
32{
33 Q_ASSERT(v.isNumber());
34 if (v.isInteger())
35 return v.integerValue();
36 return v.doubleValue();
37}
38
41};
42
43template <typename T>
45 return Encode(t);
46}
47
48template <>
52
53template <typename T>
55{
56 Q_ASSERT(value.isNumber());
57 int n = toInt32(value);
58 return static_cast<T>(n);
59}
60
61template <>
63{
64 Q_ASSERT(value.isNumber());
65 if (value.isInteger())
66 return { static_cast<quint8>(qBound(0, value.integerValue(), 255)) };
67 Q_ASSERT(value.isDouble());
68 double d = value.doubleValue();
69 // ### is there a way to optimise this?
70 if (d <= 0 || std::isnan(d))
71 return { 0 };
72 if (d >= 255)
73 return { 255 };
74 double f = std::floor(d);
75 if (f + 0.5 < d)
76 return { (quint8)(f + 1) };
77 if (d < f + 0.5)
78 return { (quint8)(f) };
79 if (int(f) % 2)
80 // odd number
81 return { (quint8)(f + 1) };
82 return { (quint8)(f) };
83}
84
85template <>
87{
88 Q_ASSERT(value.isNumber());
89 double d = toDouble(value);
90 return static_cast<float>(d);
91}
92
93template <>
95{
96 Q_ASSERT(value.isNumber());
97 return toDouble(value);
98}
99
100template <typename T>
101ReturnedValue read(const char *data) {
102 return typeToValue(*reinterpret_cast<const T *>(data));
103}
104template <typename T>
105void write(char *data, Value value)
106{
107 *reinterpret_cast<T *>(data) = valueToType<T>(value);
108}
109
110template <typename T>
112{
113 T value = valueToType<T>(v);
114 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
116 return typeToValue(value);
117}
118
119template <typename T>
121{
122 T value = valueToType<T>(v);
123 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
125 return typeToValue(value);
126}
127
128template <typename T>
130{
131 T value = valueToType<T>(v);
132 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
134 return typeToValue(value);
135}
136
137template <typename T>
139{
140 T value = valueToType<T>(v);
141 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
143 return typeToValue(value);
144}
145
146template <typename T>
148{
149 T value = valueToType<T>(v);
150 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
152 return typeToValue(value);
153}
154
155template <typename T>
157{
158 T value = valueToType<T>(v);
159 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
161 return typeToValue(value);
162}
163
164template <typename T>
166{
167 T value = valueToType<T>(v);
168 T exp = valueToType<T>(expected);
169 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
170 T old;
171 QAtomicOps<T>::testAndSetOrdered(*mem, exp, value, &old);
172 return typeToValue(old);
173}
174
175template <typename T>
177{
178 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
180 return typeToValue(val);
181}
182
183template <typename T>
185{
186 T value = valueToType<T>(v);
187 typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
189 return typeToValue(value);
190}
191
192
193template<typename T>
195{
196 return { sizeof(T),
197 name,
198 ::read<T>,
199 ::write<T>,
200 { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr },
201 nullptr,
202 nullptr,
203 nullptr
204 };
205}
206
207template<typename T>
209{
210 return { sizeof(T),
211 name,
212 ::read<T>,
213 ::write<T>,
214 { ::atomicAdd<T>, ::atomicAnd<T>, ::atomicExchange<T>, ::atomicOr<T>, ::atomicSub<T>, ::atomicXor<T> },
215 ::atomicCompareExchange<T>,
216 ::atomicLoad<T>,
217 ::atomicStore<T>
218 };
219}
220
222#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
223 TypedArrayOperations::createWithAtomics<qint8>("Int8Array"),
224 TypedArrayOperations::createWithAtomics<quint8>("Uint8Array"),
225#else
226 TypedArrayOperations::create<qint8>("Int8Array"),
227 TypedArrayOperations::create<quint8>("Uint8Array"),
228#endif
229 TypedArrayOperations::createWithAtomics<qint16>("Int16Array"),
230 TypedArrayOperations::createWithAtomics<quint16>("Uint16Array"),
231 TypedArrayOperations::createWithAtomics<qint32>("Int32Array"),
232 TypedArrayOperations::createWithAtomics<quint32>("Uint32Array"),
233 TypedArrayOperations::create<ClampedUInt8>("Uint8ClampedArray"),
234 TypedArrayOperations::create<float>("Float32Array"),
235 TypedArrayOperations::create<double>("Float64Array")
236};
237
238
244
246{
247 Scope scope(f->engine());
248 const TypedArrayCtor *that = static_cast<const TypedArrayCtor *>(f);
249
250 auto updateProto = [=](Scope &scope, Scoped<TypedArray> &a) {
251 if (newTarget->heapObject() != f->heapObject() && newTarget->isFunctionObject()) {
252 const FunctionObject *nt = static_cast<const FunctionObject *>(newTarget);
253 ScopedObject o(scope, nt->protoProperty());
254 if (o)
255 a->setPrototypeOf(o);
256 }
257 };
258
259 if (!argc || !argv[0].isObject()) {
260 // ECMA 6 22.2.1.1
261 const double l = argc ? argv[0].toInteger() : 0;
262 if (scope.hasException())
263 return Encode::undefined();
264 if (l < 0 || l > std::numeric_limits<int>::max())
265 return scope.engine->throwRangeError(QLatin1String("Index out of range."));
266
267 const double byteLength = l * operations[that->d()->type].bytesPerElement;
268
269 // TODO: This is an artificial restriction due to the fact that we store the byteLength in
270 // uint below. We should allow up to INT_MAX elements of any size.
271 if (byteLength > std::numeric_limits<uint>::max())
272 return scope.engine->throwRangeError(QLatin1String("Index out of range."));
273
274 Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(size_t(byteLength)));
275 if (scope.hasException())
276 return Encode::undefined();
277
278 Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
279 array->d()->buffer.set(scope.engine, buffer->d());
280 array->d()->byteLength = byteLength;
281 array->d()->byteOffset = 0;
282
283 updateProto(scope, array);
284 return array.asReturnedValue();
285 }
286 Scoped<TypedArray> typedArray(scope, argc ? argv[0] : Value::undefinedValue());
287 if (!!typedArray) {
288 // ECMA 6 22.2.1.2
289 Scoped<ArrayBuffer> buffer(scope, typedArray->d()->buffer);
290 if (!buffer || buffer->hasDetachedArrayData())
291 return scope.engine->throwTypeError();
292 uint srcElementSize = typedArray->bytesPerElement();
293 uint destElementSize = operations[that->d()->type].bytesPerElement;
294 uint byteLength = typedArray->byteLength();
295 uint destByteLength = byteLength*destElementSize/srcElementSize;
296
297 Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength));
298 if (scope.hasException())
299 return Encode::undefined();
300
301 Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
302 array->d()->buffer.set(scope.engine, newBuffer->d());
303 array->d()->byteLength = destByteLength;
304 array->d()->byteOffset = 0;
305
306 const char *src = buffer->constArrayData() + typedArray->byteOffset();
307 char *dest = newBuffer->arrayData();
308
309 // check if src and new type have the same size. In that case we can simply memcpy the data
310 if (srcElementSize == destElementSize) {
311 memcpy(dest, src, byteLength);
312 } else {
313 // not same size, we need to loop
314 uint l = typedArray->length();
315 TypedArrayOperations::Read read = typedArray->d()->type->read;
316 TypedArrayOperations::Write write =array->d()->type->write;
317 for (uint i = 0; i < l; ++i) {
318 Value val;
319 val.setRawValue(read(src + i*srcElementSize));
320 write(dest + i*destElementSize, val);
321 }
322 }
323
324 updateProto(scope, array);
325 return array.asReturnedValue();
326 }
327 Scoped<ArrayBuffer> buffer(scope, argc ? argv[0] : Value::undefinedValue());
328 if (!!buffer) {
329 // ECMA 6 22.2.1.4
330
331 double dbyteOffset = argc > 1 ? argv[1].toInteger() : 0;
332
333 if (buffer->hasDetachedArrayData())
334 return scope.engine->throwTypeError();
335
336 uint byteOffset = (uint)dbyteOffset;
337 uint elementSize = operations[that->d()->type].bytesPerElement;
338 if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->arrayDataLength())
339 return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
340
341 uint byteLength;
342 if (argc < 3 || argv[2].isUndefined()) {
343 byteLength = buffer->arrayDataLength() - byteOffset;
344 if (buffer->arrayDataLength() < byteOffset || byteLength % elementSize)
345 return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
346 } else {
347 double l = qBound(0., argv[2].toInteger(), (double)UINT_MAX);
348 if (scope.hasException())
349 return Encode::undefined();
350 if (buffer->hasDetachedArrayData())
351 return scope.engine->throwTypeError();
352 l *= elementSize;
353 if (buffer->arrayDataLength() - byteOffset < l)
354 return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
355 byteLength = (uint)l;
356 }
357
358 Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
359 array->d()->buffer.set(scope.engine, buffer->d());
360 array->d()->byteLength = byteLength;
361 array->d()->byteOffset = byteOffset;
362
363 updateProto(scope, array);
364 return array.asReturnedValue();
365 }
366
367 // ECMA 6 22.2.1.3
368
369 ScopedObject o(scope, argc ? argv[0] : Value::undefinedValue());
370 uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX);
371 if (scope.hasException())
372 return scope.engine->throwTypeError();
373
374 uint elementSize = operations[that->d()->type].bytesPerElement;
375 size_t bufferSize;
376 if (qMulOverflow(size_t(l), size_t(elementSize), &bufferSize))
377 return scope.engine->throwRangeError(QLatin1String("new TypedArray: invalid length"));
378 Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(bufferSize));
379 if (scope.hasException())
380 return Encode::undefined();
381
382 Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
383 array->d()->buffer.set(scope.engine, newBuffer->d());
384 array->d()->byteLength = l * elementSize;
385 array->d()->byteOffset = 0;
386
387 uint idx = 0;
388 char *b = newBuffer->arrayData();
389 ScopedValue val(scope);
390 while (idx < l) {
391 val = o->get(idx);
392 val = val->convertedToNumber();
393 if (scope.hasException())
394 return Encode::undefined();
395 array->d()->type->write(b, val);
396 if (scope.hasException())
397 return Encode::undefined();
398 ++idx;
399 b += elementSize;
400 }
401
402 updateProto(scope, array);
403 return array.asReturnedValue();
404}
405
407{
408 return f->engine()->throwTypeError(QStringLiteral("calling a TypedArray constructor without new is invalid"));
409}
410
411void Heap::TypedArray::init(Type t)
412{
413 Object::init();
414 type = operations + static_cast<int>(t);
415 arrayType = static_cast<int>(t);
416}
417
418Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t)
419{
420 Scope scope(e);
421 Scoped<InternalClass> ic(scope, e->newInternalClass(staticVTable(), e->typedArrayPrototype + static_cast<int>(t)));
422 return e->memoryManager->allocObject<TypedArray>(ic->d(), t);
423}
424
425ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
426{
427 const bool isArrayIndex = id.isArrayIndex();
428 if (!isArrayIndex && !id.isCanonicalNumericIndexString())
429 return Object::virtualGet(m, id, receiver, hasProperty);
430
431 Scope scope(static_cast<const Object *>(m)->engine());
432 Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m));
433 if (a->hasDetachedArrayData())
434 return scope.engine->throwTypeError();
435
436 if (!isArrayIndex || id.asArrayIndex() >= a->length()) {
437 if (hasProperty)
438 *hasProperty = false;
439 return Encode::undefined();
440 }
441
442 uint bytesPerElement = a->bytesPerElement();
443 uint byteOffset = a->byteOffset() + id.asArrayIndex() * bytesPerElement;
444 Q_ASSERT(byteOffset + bytesPerElement <= a->arrayDataLength());
445
446 if (hasProperty)
447 *hasProperty = true;
448 return a->d()->type->read(a->constArrayData() + byteOffset);
449}
450
452{
453 const bool isArrayIndex = id.isArrayIndex();
454 if (!isArrayIndex && !id.isCanonicalNumericIndexString())
455 return Object::virtualHasProperty(m, id);
456
457 const TypedArray *a = static_cast<const TypedArray *>(m);
458 if (a->hasDetachedArrayData()) {
459 a->engine()->throwTypeError();
460 return false;
461 }
462 return isArrayIndex && id.asArrayIndex() < a->length();
463}
464
466{
467 if (!id.isArrayIndex() && !id.isCanonicalNumericIndexString())
468 return Object::virtualGetOwnProperty(m, id, p);
469
470 bool hasProperty = false;
471 ReturnedValue v = virtualGet(m, id, m, &hasProperty);
472 if (p)
473 p->value = v;
474 return hasProperty ? Attr_NotConfigurable : PropertyAttributes();
475}
476
478{
479 const bool isArrayIndex = id.isArrayIndex();
480 if (!isArrayIndex && !id.isCanonicalNumericIndexString())
481 return Object::virtualPut(m, id, value, receiver);
482
483 ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
484 if (v4->hasException)
485 return false;
486
487 Scope scope(v4);
488 Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
489 if (a->hasDetachedArrayData())
490 return scope.engine->throwTypeError();
491
492 if (!isArrayIndex)
493 return false;
494
495 const uint index = id.asArrayIndex();
496 if (index >= a->length())
497 return false;
498
499 uint bytesPerElement = a->bytesPerElement();
500 uint byteOffset = a->byteOffset() + index * bytesPerElement;
501 Q_ASSERT(byteOffset + bytesPerElement <= a->arrayDataLength());
502
503 Value v = Value::fromReturnedValue(value.convertedToNumber());
504 if (scope.hasException() || a->hasDetachedArrayData())
505 return scope.engine->throwTypeError();
506 a->d()->type->write(a->arrayData() + byteOffset, v);
507 return true;
508}
509
511{
512 if (!id.isArrayIndex()) {
513 return !id.isCanonicalNumericIndexString()
515 }
516
517 const uint index = id.asArrayIndex();
518 TypedArray *a = static_cast<TypedArray *>(m);
519 if (index >= a->length() || attrs.isAccessor())
520 return false;
521
522 if (attrs.hasConfigurable() && attrs.isConfigurable())
523 return false;
524 if (attrs.hasEnumerable() && !attrs.isEnumerable())
525 return false;
526 if (attrs.hasWritable() && !attrs.isWritable())
527 return false;
528 if (!p->value.isEmpty()) {
529 ExecutionEngine *engine = a->engine();
530
531 Value v = Value::fromReturnedValue(p->value.convertedToNumber());
532 if (engine->hasException || a->hasDetachedArrayData())
533 return engine->throwTypeError();
534 uint bytesPerElement = a->bytesPerElement();
535 uint byteOffset = a->byteOffset() + index * bytesPerElement;
536 Q_ASSERT(byteOffset + bytesPerElement <= a->arrayDataLength());
537 a->d()->type->write(a->arrayData() + byteOffset, v);
538 }
539 return true;
540}
541
543{
545 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
546
547};
548
550{
551 const TypedArray *a = static_cast<const TypedArray *>(o);
552 if (arrayIndex < a->length()) {
553 if (attrs)
556 if (pd) {
557 bool hasProperty = false;
558 pd->value = TypedArray::virtualGet(a, id, a, &hasProperty);
559 }
560 ++arrayIndex;
561 return id;
562 }
563
564 arrayIndex = UINT_MAX;
566}
567
573
575{
576 Scope scope(engine);
577 ScopedObject o(scope);
578
579 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(3));
580 ctor->defineReadonlyProperty(engine->id_prototype(), *this);
581 ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Value::fromInt32(operations[static_cast<int>(ctor->d()->type)].bytesPerElement));
582 ctor->setPrototypeOf(engine->intrinsicTypedArrayCtor());
583
586 defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Value::fromInt32(operations[static_cast<int>(ctor->d()->type)].bytesPerElement));
587}
588
590{
591 ExecutionEngine *v4 = b->engine();
592 const TypedArray *v = thisObject->as<TypedArray>();
593 if (!v)
594 return v4->throwTypeError();
595
596 return v->d()->buffer->asReturnedValue();
597}
598
600{
601 ExecutionEngine *v4 = b->engine();
602 const TypedArray *v = thisObject->as<TypedArray>();
603 if (!v)
604 return v4->throwTypeError();
605
606 if (v->hasDetachedArrayData())
607 return Encode(0);
608
609 return Encode(v->byteLength());
610}
611
613{
614 ExecutionEngine *v4 = b->engine();
615 const TypedArray *v = thisObject->as<TypedArray>();
616 if (!v)
617 return v4->throwTypeError();
618
619 if (v->hasDetachedArrayData())
620 return Encode(0);
621
622 return Encode(v->byteOffset());
623}
624
626{
627 ExecutionEngine *v4 = b->engine();
628 const TypedArray *v = thisObject->as<TypedArray>();
629 if (!v)
630 return v4->throwTypeError();
631
632 if (v->hasDetachedArrayData())
633 return Encode(0);
634
635 return Encode(v->length());
636}
637
639{
640 Scope scope(f);
641 Scoped<TypedArray> instance(scope, thisObject);
642 if (!instance || instance->hasDetachedArrayData())
643 return scope.engine->throwTypeError();
644
645 if (!argc)
646 return instance->asReturnedValue();
647
648 const double len = instance->length();
649 Q_ASSERT(std::isfinite(len));
650
651 const double target = argv[0].toInteger();
652
653 const double start = (argc > 1)
654 ? argv[1].toInteger()
655 : 0;
656
657 const double end = (argc > 2 && !argv[2].isUndefined())
658 ? argv[2].toInteger()
659 : len;
660
661 const double fin = end < 0
662 ? std::max(len + end, 0.0)
663 : std::min(end, len);
664
665 const qsizetype from = start < 0
666 ? std::max(len + start, 0.0)
667 : std::min(start, len);
668
669 const qsizetype to = target < 0
670 ? std::max(len + target, 0.0)
671 : std::min(target, len);
672
673 const qsizetype count = std::min(fin - from, len - to);
674
675 if (count <= 0)
676 return instance->asReturnedValue();
677
678 if (from != to) {
679 int elementSize = instance->bytesPerElement();
680 char *data = instance->arrayData() + instance->byteOffset();
681 memmove(data + to * elementSize, data + from * elementSize, count * elementSize);
682 }
683
684 return instance->asReturnedValue();
685}
686
688{
689 Scope scope(b);
690 Scoped<TypedArray> v(scope, thisObject);
691 if (!v || v->hasDetachedArrayData())
692 return scope.engine->throwTypeError();
693
694 Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(v));
695 ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
696 return ao->asReturnedValue();
697}
698
700{
701 Scope scope(b);
702 Scoped<TypedArray> v(scope, thisObject);
703 if (!v || v->hasDetachedArrayData())
704 return scope.engine->throwTypeError();
705
706 uint len = v->length();
707
708 if (!argc || !argv->isFunctionObject())
710 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
711
712 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
713 ScopedValue r(scope);
714 Value *arguments = scope.alloc(3);
715
716 const char *data = v->constArrayData();
717 uint bytesPerElement = v->bytesPerElement();
718 uint byteOffset = v->byteOffset();
719
720 bool ok = true;
721 for (uint k = 0; ok && k < len; ++k) {
722 if (v->hasDetachedArrayData())
723 return scope.engine->throwTypeError();
724
725 arguments[0] = v->d()->type->read(data + byteOffset + k * bytesPerElement);
726
728 arguments[2] = v;
729 r = callback->call(that, arguments, 3);
731 ok = r->toBoolean();
732 }
733 return Encode(ok);
734}
735
737{
738 Scope scope(b);
739 Scoped<TypedArray> v(scope, thisObject);
740 if (!v || v->hasDetachedArrayData())
741 return scope.engine->throwTypeError();
742
743 uint len = v->length();
744 double dlen = len;
745 double relativeStart = argc > 1 ? argv[1].toInteger() : 0.;
746 double relativeEnd = len;
747 if (argc > 2 && !argv[2].isUndefined())
748 relativeEnd = argv[2].toInteger();
749
750 uint k = 0;
751 uint fin = 0;
752
753 if (relativeStart < 0) {
754 k = static_cast<uint>(std::max(len+relativeStart, 0.));
755 } else {
756 k = static_cast<uint>(std::min(relativeStart, dlen));
757 }
758
759 if (relativeEnd < 0) {
760 fin = static_cast<uint>(std::max(len + relativeEnd, 0.));
761 } else {
762 fin = static_cast<uint>(std::min(relativeEnd, dlen));
763 }
764
765 double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN();
767 if (scope.hasException() || v->hasDetachedArrayData())
768 return scope.engine->throwTypeError();
769
770 char *data = v->arrayData();
771 uint bytesPerElement = v->bytesPerElement();
772 uint byteOffset = v->byteOffset();
773
774 while (k < fin) {
775 v->d()->type->write(data + byteOffset + k * bytesPerElement, value);
776 k++;
777 }
778
779 return v.asReturnedValue();
780}
781
783{
784 const FunctionObject *constructor = instance->speciesConstructor(scope, scope.engine->typedArrayCtors + instance->d()->arrayType);
785 if (!constructor) {
786 scope.engine->throwTypeError();
787 return nullptr;
788 }
789
790 Value *arguments = scope.alloc(1);
791 arguments[0] = Encode(len);
792 Scoped<TypedArray> a(scope, constructor->callAsConstructor(arguments, 1));
793 if (!a || a->hasDetachedArrayData() || a->length() < len) {
794 scope.engine->throwTypeError();
795 return nullptr;
796 }
797 return a;
798}
799
801{
802 Scope scope(b);
803 Scoped<TypedArray> instance(scope, thisObject);
804 if (!instance || instance->hasDetachedArrayData())
805 return scope.engine->throwTypeError();
806
807 uint len = instance->length();
808
809 if (!argc || !argv->isFunctionObject())
811 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
812
813 ScopedValue selected(scope);
814 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
815 Value *arguments = scope.alloc(3);
817
818 uint to = 0;
819 for (uint k = 0; k < len; ++k) {
820 if (instance->hasDetachedArrayData())
821 return scope.engine->throwTypeError();
822 bool exists;
823 arguments[0] = instance->get(k, &exists);
824 if (!exists)
825 continue;
826
828 arguments[2] = instance;
829 selected = callback->call(that, arguments, 3);
831 if (selected->toBoolean()) {
832 ++arguments;
833 scope.alloc(1);
834 ++to;
835 }
836 }
837
838 TypedArray *a = typedArraySpeciesCreate(scope, instance, to);
839 if (!a)
840 return Encode::undefined();
841
842 for (uint i = 0; i < to; ++i)
843 a->put(i, list[i]);
844
845 return a->asReturnedValue();
846}
847
849{
850 Scope scope(b);
851 Scoped<TypedArray> v(scope, thisObject);
852 if (!v || v->hasDetachedArrayData())
853 return scope.engine->throwTypeError();
854
855 uint len = v->length();
856
857 if (!argc || !argv[0].isFunctionObject())
859 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
860
861 ScopedValue result(scope);
862 Value *arguments = scope.alloc(3);
863
864 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
865
866 for (uint k = 0; k < len; ++k) {
867 if (v->hasDetachedArrayData())
868 return scope.engine->throwTypeError();
869 arguments[0] = v->get(k);
871
873 arguments[2] = v;
874 result = callback->call(that, arguments, 3);
875
877 if (result->toBoolean())
878 return arguments[0].asReturnedValue();
879 }
880
882}
883
885{
886 Scope scope(b);
887 Scoped<TypedArray> v(scope, thisObject);
888 if (!v || v->hasDetachedArrayData())
889 return scope.engine->throwTypeError();
890
891 uint len = v->length();
892
893 if (!argc || !argv[0].isFunctionObject())
895 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
896
897 ScopedValue result(scope);
898 Value *arguments = scope.alloc(3);
899
900 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
901
902 for (uint k = 0; k < len; ++k) {
903 if (v->hasDetachedArrayData())
904 return scope.engine->throwTypeError();
905 arguments[0] = v->get(k);
907
909 arguments[2] = v;
910 result = callback->call(that, arguments, 3);
911
913 if (result->toBoolean())
914 return Encode(k);
915 }
916
917 return Encode(-1);
918}
919
921{
922 Scope scope(b);
923 Scoped<TypedArray> v(scope, thisObject);
924 if (!v || v->hasDetachedArrayData())
925 return scope.engine->throwTypeError();
926
927 uint len = v->length();
928
929 if (!argc || !argv->isFunctionObject())
931 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
932
933 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
934 Value *arguments = scope.alloc(3);
935
936 for (uint k = 0; k < len; ++k) {
937 if (v->hasDetachedArrayData())
938 return scope.engine->throwTypeError();
939 bool exists;
940 arguments[0] = v->get(k, &exists);
941 if (!exists)
942 continue;
943
945 arguments[2] = v;
946 callback->call(that, arguments, 3);
947 }
949}
950
951
953{
954 Scope scope(b);
955 Scoped<TypedArray> v(scope, thisObject);
956 if (!v || v->hasDetachedArrayData())
957 return scope.engine->throwTypeError();
958
959 uint len = v->length();
960 if (len == 0) {
961 return Encode(false);
962 }
963
964 double n = 0;
965 if (argc > 1 && !argv[1].isUndefined()) {
966 n = argv[1].toInteger();
967 }
968
969 double k = 0;
970 if (n >= 0) {
971 k = n;
972 } else {
973 k = len + n;
974 if (k < 0) {
975 k = 0;
976 }
977 }
978
979 while (k < len) {
980 ScopedValue val(scope, v->get(k));
981 if (val->sameValueZero(argv[0])) {
982 return Encode(true);
983 }
984 k++;
985 }
986
987 return Encode(false);
988}
989
991{
992 Scope scope(b);
993 Scoped<TypedArray> v(scope, thisObject);
994 if (!v || v->hasDetachedArrayData())
995 return scope.engine->throwTypeError();
996
997 uint len = v->length();
998 if (!len)
999 return Encode(-1);
1000
1001 ScopedValue searchValue(scope, argc ? argv[0] : Value::undefinedValue());
1002 uint fromIndex = 0;
1003
1004 if (argc >= 2) {
1005 double f = argv[1].toInteger();
1007 if (f >= len)
1008 return Encode(-1);
1009 if (f < 0)
1010 f = qMax(len + f, 0.);
1011 fromIndex = (uint) f;
1012 }
1013
1014 if (v->isStringObject()) {
1015 ScopedValue value(scope);
1016 for (uint k = fromIndex; k < len; ++k) {
1017 bool exists;
1018 value = v->get(k, &exists);
1019 if (exists && RuntimeHelpers::strictEqual(value, searchValue))
1020 return Encode(k);
1021 }
1022 return Encode(-1);
1023 }
1024
1025 ScopedValue value(scope);
1026
1027 for (uint i = fromIndex; i < len; ++i) {
1028 bool exists;
1029 value = v->get(i, &exists);
1031 if (exists && RuntimeHelpers::strictEqual(value, searchValue))
1032 return Encode(i);
1033 }
1034 return Encode(-1);
1035}
1036
1038 const FunctionObject *functionObject, const Value *thisObject, const Value *argv, int argc)
1039{
1040 Scope scope(functionObject);
1041 Scoped<TypedArray> typedArray(scope, thisObject);
1042 if (!typedArray || typedArray->hasDetachedArrayData())
1043 return scope.engine->throwTypeError();
1044
1045 // We cannot optimize the resolution of the argument away if length is 0.
1046 // It may have side effects.
1047 ScopedValue argument(scope, argc ? argv[0] : Value::undefinedValue());
1048 const QString separator = argument->isUndefined()
1049 ? QStringLiteral(",")
1050 : argument->toQString();
1051
1052 const quint32 length = typedArray->length();
1053 if (!length)
1054 return Encode(scope.engine->newString());
1055
1057
1058 ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
1059 ScopedValue value(scope, typedArray->get(name));
1060 if (!value->isNullOrUndefined())
1061 result = value->toQString();
1062
1063 for (quint32 i = 1; i < length; ++i) {
1064 result += separator;
1065
1066 name = Value::fromDouble(i).toString(scope.engine);
1067 value = typedArray->get(name);
1069
1070 if (!value->isNullOrUndefined())
1071 result += value->toQString();
1072 }
1073
1074 return Encode(scope.engine->newString(result));
1075}
1076
1078{
1079 Scope scope(b);
1080 Scoped<TypedArray> v(scope, thisObject);
1081 if (!v || v->hasDetachedArrayData())
1082 return scope.engine->throwTypeError();
1083
1084 Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(v));
1085 ao->d()->iterationKind = IteratorKind::KeyIteratorKind;
1086 return ao->asReturnedValue();
1087}
1088
1089
1091{
1092 Scope scope(b);
1093 Scoped<TypedArray> instance(scope, thisObject);
1094 if (!instance || instance->hasDetachedArrayData())
1095 return scope.engine->throwTypeError();
1096
1097 uint len = instance->length();
1098 if (!len)
1099 return Encode(-1);
1100
1101 ScopedValue searchValue(scope);
1102 uint fromIndex = len;
1103
1104 if (argc >= 1)
1105 searchValue = argv[0];
1106 else
1107 searchValue = Value::undefinedValue();
1108
1109 if (argc >= 2) {
1110 double f = argv[1].toInteger();
1112 if (f > 0)
1113 f = qMin(f, (double)(len - 1));
1114 else if (f < 0) {
1115 f = len + f;
1116 if (f < 0)
1117 return Encode(-1);
1118 }
1119 fromIndex = (uint) f + 1;
1120 }
1121
1122 ScopedValue value(scope);
1123 for (uint k = fromIndex; k > 0;) {
1124 --k;
1125 bool exists;
1126 value = instance->get(k, &exists);
1127 if (exists && RuntimeHelpers::strictEqual(value, searchValue))
1128 return Encode(k);
1129 }
1130 return Encode(-1);
1131}
1132
1134{
1135 Scope scope(b);
1136 Scoped<TypedArray> instance(scope, thisObject);
1137 if (!instance || instance->hasDetachedArrayData())
1138 return scope.engine->throwTypeError();
1139
1140 uint len = instance->length();
1141
1142 if (!argc || !argv->isFunctionObject())
1144 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
1145
1146 TypedArray *a = typedArraySpeciesCreate(scope, instance, len);
1147 if (!a)
1148 return Encode::undefined();
1149
1150 ScopedValue v(scope);
1151 ScopedValue mapped(scope);
1152 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
1153 Value *arguments = scope.alloc(3);
1154
1155 for (uint k = 0; k < len; ++k) {
1156 if (instance->hasDetachedArrayData())
1157 return scope.engine->throwTypeError();
1158 arguments[0] = instance->get(k);
1159
1161 arguments[2] = instance;
1162 mapped = callback->call(that, arguments, 3);
1164 a->put(k, mapped);
1165 }
1166 return a->asReturnedValue();
1167}
1168
1170{
1171 Scope scope(b);
1172 Scoped<TypedArray> instance(scope, thisObject);
1173 if (!instance || instance->hasDetachedArrayData())
1174 return scope.engine->throwTypeError();
1175
1176 uint len = instance->length();
1177
1178 if (!argc || !argv->isFunctionObject())
1180 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
1181
1182 uint k = 0;
1183 ScopedValue acc(scope);
1184 ScopedValue v(scope);
1185
1186 if (argc > 1) {
1187 acc = argv[1];
1188 } else {
1189 bool kPresent = false;
1190 while (k < len && !kPresent) {
1191 v = instance->get(k, &kPresent);
1192 if (kPresent)
1193 acc = v;
1194 ++k;
1195 }
1196 if (!kPresent)
1198 }
1199
1200 Value *arguments = scope.alloc(4);
1201
1202 while (k < len) {
1203 if (instance->hasDetachedArrayData())
1204 return scope.engine->throwTypeError();
1205 bool kPresent;
1206 v = instance->get(k, &kPresent);
1207 if (kPresent) {
1208 arguments[0] = acc;
1209 arguments[1] = v;
1211 arguments[3] = instance;
1212 acc = callback->call(nullptr, arguments, 4);
1214 }
1215 ++k;
1216 }
1217 return acc->asReturnedValue();
1218}
1219
1221{
1222 Scope scope(b);
1223 Scoped<TypedArray> instance(scope, thisObject);
1224 if (!instance || instance->hasDetachedArrayData())
1225 return scope.engine->throwTypeError();
1226
1227 uint len = instance->length();
1228
1229 if (!argc || !argv->isFunctionObject())
1231 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
1232
1233 if (len == 0) {
1234 if (argc == 1)
1236 return argv[1].asReturnedValue();
1237 }
1238
1239 uint k = len;
1240 ScopedValue acc(scope);
1241 ScopedValue v(scope);
1242 if (argc > 1) {
1243 acc = argv[1];
1244 } else {
1245 bool kPresent = false;
1246 while (k > 0 && !kPresent) {
1247 v = instance->get(k - 1, &kPresent);
1248 if (kPresent)
1249 acc = v;
1250 --k;
1251 }
1252 if (!kPresent)
1254 }
1255
1256 Value *arguments = scope.alloc(4);
1257
1258 while (k > 0) {
1259 if (instance->hasDetachedArrayData())
1260 return scope.engine->throwTypeError();
1261 bool kPresent;
1262 v = instance->get(k - 1, &kPresent);
1263 if (kPresent) {
1264 arguments[0] = acc;
1265 arguments[1] = v;
1266 arguments[2] = Value::fromDouble(k - 1);
1267 arguments[3] = instance;
1268 acc = callback->call(nullptr, arguments, 4);
1270 }
1271 --k;
1272 }
1273 return acc->asReturnedValue();
1274}
1275
1277{
1278 Scope scope(b);
1279 Scoped<TypedArray> instance(scope, thisObject);
1280 if (!instance || instance->hasDetachedArrayData())
1281 return scope.engine->throwTypeError();
1282
1283 uint length = instance->length();
1284
1285 int lo = 0, hi = length - 1;
1286
1287 ScopedValue lval(scope);
1288 ScopedValue hval(scope);
1289 for (; lo < hi; ++lo, --hi) {
1290 bool loExists, hiExists;
1291 lval = instance->get(lo, &loExists);
1292 hval = instance->get(hi, &hiExists);
1293 Q_ASSERT(hiExists && loExists);
1294 bool ok;
1295 ok = instance->put(lo, hval);
1296 Q_ASSERT(ok);
1297 ok = instance->put(hi, lval);
1298 Q_ASSERT(ok);
1299 }
1300 return instance->asReturnedValue();
1301}
1302
1304{
1305 Scope scope(b);
1306 Scoped<TypedArray> instance(scope, thisObject);
1307 if (!instance || instance->hasDetachedArrayData())
1308 return scope.engine->throwTypeError();
1309
1310 uint len = instance->length();
1311
1312 if (!argc || !argv->isFunctionObject())
1314 const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
1315
1316 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
1317 ScopedValue result(scope);
1318 Value *arguments = scope.alloc(3);
1319
1320 for (uint k = 0; k < len; ++k) {
1321 if (instance->hasDetachedArrayData())
1322 return scope.engine->throwTypeError();
1323 bool exists;
1324 arguments[0] = instance->get(k, &exists);
1325 if (!exists)
1326 continue;
1327
1329 arguments[2] = instance;
1330 result = callback->call(that, arguments, 3);
1332 if (result->toBoolean())
1333 return Encode(true);
1334 }
1335 return Encode(false);
1336}
1337
1338
1340{
1341 Scope scope(b);
1342 Scoped<TypedArray> v(scope, thisObject);
1343 if (!v || v->hasDetachedArrayData())
1344 return scope.engine->throwTypeError();
1345
1346 Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(v));
1347 ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
1348 return ao->asReturnedValue();
1349}
1350
1352{
1353 Scope scope(b);
1354 Scoped<TypedArray> a(scope, *thisObject);
1355 if (!a)
1356 return scope.engine->throwTypeError();
1357 Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
1358
1359 double doffset = argc >= 2 ? argv[1].toInteger() : 0;
1360 if (scope.hasException())
1362 if (!buffer || buffer->hasDetachedArrayData())
1363 return scope.engine->throwTypeError();
1364
1365 if (doffset < 0 || doffset >= UINT_MAX)
1366 RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
1367 uint offset = (uint)doffset;
1368 uint elementSize = a->bytesPerElement();
1369
1370 Scoped<TypedArray> srcTypedArray(scope, argv[0]);
1371 if (!srcTypedArray) {
1372 // src is a regular object
1373 ScopedObject o(scope, argv[0].toObject(scope.engine));
1374 if (scope.hasException() || !o)
1375 return scope.engine->throwTypeError();
1376
1377 double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber();
1378 uint l = (uint)len;
1379 if (scope.hasException() || l != len)
1380 return scope.engine->throwTypeError();
1381
1382 const uint aLength = a->length();
1383 if (offset > aLength || l > aLength - offset)
1384 RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
1385
1386 uint idx = 0;
1387 if (buffer->hasDetachedArrayData())
1388 return scope.engine->throwTypeError();
1389 char *b = buffer->arrayData() + a->byteOffset() + offset*elementSize;
1390 ScopedValue val(scope);
1391 while (idx < l) {
1392 val = o->get(idx);
1393 if (scope.hasException())
1394 return Encode::undefined();
1395 val = val->convertedToNumber();
1396 if (scope.hasException() || buffer->hasDetachedArrayData())
1397 return scope.engine->throwTypeError();
1398 a->d()->type->write(b, val);
1399 if (scope.hasException())
1401 ++idx;
1402 b += elementSize;
1403 }
1405 }
1406
1407 // src is a typed array
1408 Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer);
1409 if (!srcBuffer || srcBuffer->hasDetachedArrayData())
1410 return scope.engine->throwTypeError();
1411
1412 uint l = srcTypedArray->length();
1413
1414 const uint aLength = a->length();
1415 if (offset > aLength || l > aLength - offset)
1416 RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
1417
1418 char *dest = buffer->arrayData() + a->byteOffset() + offset*elementSize;
1419 const char *src = srcBuffer->d()->constArrayData() + srcTypedArray->byteOffset();
1420 if (srcTypedArray->d()->type == a->d()->type) {
1421 // same type of typed arrays, use memmove (as srcbuffer and buffer could be the same)
1422 memmove(dest, src, srcTypedArray->byteLength());
1424 }
1425
1426 char *srcCopy = nullptr;
1427 if (buffer->d() == srcBuffer->d()) {
1428 // same buffer, need to take a temporary copy, to not run into problems
1429 srcCopy = new char[srcTypedArray->byteLength()];
1430 memcpy(srcCopy, src, srcTypedArray->byteLength());
1431 src = srcCopy;
1432 }
1433
1434 // typed arrays of different kind, need to manually loop
1435 uint srcElementSize = srcTypedArray->bytesPerElement();
1436 TypedArrayOperations::Read read = srcTypedArray->d()->type->read;
1437 TypedArrayOperations::Write write = a->d()->type->write;
1438 for (uint i = 0; i < l; ++i) {
1439 Value val;
1440 val.setRawValue(read(src + i*srcElementSize));
1441 write(dest + i*elementSize, val);
1442 }
1443
1444 if (srcCopy)
1445 delete [] srcCopy;
1446
1448}
1449
1451{
1452 Scope scope(b);
1453 Scoped<TypedArray> instance(scope, thisObject);
1454 if (!instance || instance->hasDetachedArrayData())
1455 return scope.engine->throwTypeError();
1456
1457 uint len = instance->length();
1458
1459 double s = (argc ? argv[0] : Value::undefinedValue()).toInteger();
1460 uint start;
1461 if (s < 0)
1462 start = (uint)qMax(len + s, 0.);
1463 else if (s > len)
1464 start = len;
1465 else
1466 start = (uint) s;
1467 uint end = len;
1468 if (argc > 1 && !argv[1].isUndefined()) {
1469 double e = argv[1].toInteger();
1470 if (e < 0)
1471 end = (uint)qMax(len + e, 0.);
1472 else if (e > len)
1473 end = len;
1474 else
1475 end = (uint) e;
1476 }
1477 uint count = start > end ? 0 : end - start;
1478
1479 TypedArray *a = typedArraySpeciesCreate(scope, instance, count);
1480 if (!a)
1481 return Encode::undefined();
1482
1483 ScopedValue v(scope);
1484 uint n = 0;
1485 for (uint i = start; i < end; ++i) {
1486 if (instance->hasDetachedArrayData())
1487 return scope.engine->throwTypeError();
1488 v = instance->get(i);
1489 if (a->hasDetachedArrayData())
1490 return scope.engine->throwTypeError();
1491 a->put(n, v);
1492 ++n;
1493 }
1494 return a->asReturnedValue();
1495}
1496
1497ReturnedValue IntrinsicTypedArrayPrototype::method_subarray(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
1498{
1499 Scope scope(builtin);
1500 Scoped<TypedArray> a(scope, *thisObject);
1501
1502 if (!a)
1503 return scope.engine->throwTypeError();
1504
1505 Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
1507
1508 int len = a->length();
1509 double b = argc > 0 ? argv[0].toInteger() : 0;
1510 if (b < 0)
1511 b = len + b;
1512 uint begin = (uint)qBound(0., b, (double)len);
1513
1514 double e = argc < 2 || argv[1].isUndefined() ? len : argv[1].toInteger();
1515 if (e < 0)
1516 e = len + e;
1517 uint end = (uint)qBound(0., e, (double)len);
1518 if (end < begin)
1519 end = begin;
1520
1521 if (scope.hasException())
1523
1524 int newLen = end - begin;
1525
1526 ScopedFunctionObject constructor(scope, a->speciesConstructor(scope, scope.engine->typedArrayCtors + a->d()->arrayType));
1527 if (!constructor)
1528 return scope.engine->throwTypeError();
1529
1530 Value *arguments = scope.alloc(3);
1531 arguments[0] = buffer;
1532 arguments[1] = Encode(a->byteOffset() + begin * a->bytesPerElement());
1533 arguments[2] = Encode(newLen);
1534 a = constructor->callAsConstructor(arguments, 3);
1535 if (!a || a->hasDetachedArrayData())
1536 return scope.engine->throwTypeError();
1537 return a->asReturnedValue();
1538}
1539
1541{
1542 Scope scope(b);
1543 Scoped<TypedArray> instance(scope, thisObject);
1544 if (!instance || instance->hasDetachedArrayData())
1545 return scope.engine->throwTypeError();
1546
1547 uint len = instance->length();
1548 const QString separator = QStringLiteral(",");
1549
1550 QString R;
1551
1552 ScopedValue v(scope);
1553 ScopedString s(scope);
1554
1555 ScopedPropertyKey tolocaleString(scope, scope.engine->id_toLocaleString()->toPropertyKey());
1556 Q_ASSERT(!scope.engine->hasException);
1557
1558 for (uint k = 0; k < len; ++k) {
1559 if (instance->hasDetachedArrayData())
1560 return scope.engine->throwTypeError();
1561 if (k)
1562 R += separator;
1563
1564 v = instance->get(k);
1565 Q_ASSERT(!v->isNullOrUndefined()); // typed array cannot hold null or undefined
1566
1567 ScopedObject valueAsObject(scope, v->toObject(scope.engine));
1568 Q_ASSERT(valueAsObject); // only null or undefined cannot be converted to object
1569
1570 ScopedFunctionObject function(scope, valueAsObject->get(tolocaleString));
1571 if (!function)
1572 return scope.engine->throwTypeError();
1573
1574 v = function->call(valueAsObject, nullptr, 0);
1575 if (scope.hasException())
1576 return Encode::undefined();
1577
1578 s = v->toString(scope.engine);
1579 if (scope.hasException())
1580 return Encode::undefined();
1581
1582 R += s->toQString();
1583 }
1584 return scope.engine->newString(R)->asReturnedValue();
1585}
1586
1588{
1589 const TypedArray *a = thisObject->as<TypedArray>();
1590 if (!a)
1591 return Encode::undefined();
1592
1593 return a->engine()->newString(QString::fromLatin1(a->d()->type->name))->asReturnedValue();
1594}
1595
1596static bool validateTypedArray(const Object *o)
1597{
1598 const TypedArray *a = o->as<TypedArray>();
1599 if (!a)
1600 return false;
1601 if (a->hasDetachedArrayData())
1602 return false;
1603 return true;
1604}
1605
1606ReturnedValue IntrinsicTypedArrayCtor::method_of(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
1607{
1608 Scope scope(f);
1609 int len = argc;
1610 const Value *items = argv;
1611 const FunctionObject *C = thisObject->as<FunctionObject>();
1612 if (!C || !C->isConstructor())
1613 return scope.engine->throwTypeError();
1614
1615 Value lenValue = Value::fromInt32(len);
1616 ScopedObject newObj(scope, C->callAsConstructor(&lenValue, 1));
1617 if (scope.hasException())
1618 return Encode::undefined();
1619 if (!::validateTypedArray(newObj))
1620 return scope.engine->throwTypeError();
1621 TypedArray *a = newObj->as<TypedArray>();
1622 Q_ASSERT(a);
1623 if (a->length() < static_cast<uint>(len))
1624 return scope.engine->throwTypeError();
1625
1626 for (int k = 0; k < len; ++k) {
1627 newObj->put(PropertyKey::fromArrayIndex(k), items[k]);
1628 }
1629 return newObj->asReturnedValue();
1630}
1631
1632ReturnedValue IntrinsicTypedArrayCtor::method_from(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
1633{
1634 Scope scope(f);
1635 ScopedObject itemsObject(scope, argv[0]);
1636 bool usingIterator = false;
1637
1639 Value *mapArguments = nullptr;
1640 if (argc > 1) {
1641 mapfn = ScopedFunctionObject(scope, argv[1]);
1642 if (!mapfn)
1643 return scope.engine->throwTypeError(QString::fromLatin1("%1 is not a function").arg(argv[1].toQStringNoThrow()));
1644 mapArguments = scope.alloc(2);
1645 }
1646
1647 // Iterator validity check goes after map function validity has been checked.
1648 if (itemsObject) {
1649 // If the object claims to support iterators, then let's try use them.
1650 ScopedValue it(scope, itemsObject->get(scope.engine->symbol_iterator()));
1652 if (!it->isNullOrUndefined()) {
1653 ScopedFunctionObject itfunc(scope, it);
1654 if (!itfunc)
1655 return scope.engine->throwTypeError();
1656 usingIterator = true;
1657 }
1658 }
1659
1660 ScopedValue thisArg(scope);
1661 if (argc > 2)
1662 thisArg = argv[2];
1663
1664 const FunctionObject *C = thisObject->as<FunctionObject>();
1665
1666 if (usingIterator) {
1667 // Item iteration supported, so let's go ahead and try use that.
1669
1670 qint64 iterableLength = 0;
1671 Value *nextValue = scope.alloc(1);
1672 ScopedValue done(scope);
1673
1674 ScopedObject lengthIterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
1675 CHECK_EXCEPTION(); // symbol_iterator threw; whoops.
1676 if (!lengthIterator) {
1677 return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
1678 }
1679
1680 forever {
1681 // Here we calculate the length of the iterable range.
1682 if (iterableLength > (static_cast<qint64>(1) << 53) - 1) {
1683 ScopedValue error(scope, scope.engine->throwTypeError());
1684 return Runtime::IteratorClose::call(scope.engine, lengthIterator);
1685 }
1686 // Retrieve the next value. If the iteration ends, we're done here.
1687 done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, lengthIterator, nextValue));
1688 if (scope.hasException())
1689 return Runtime::IteratorClose::call(scope.engine, lengthIterator);
1690 if (done->toBoolean()) {
1691 break;
1692 }
1693 iterableLength++;
1694 }
1695
1696 // Constructor validity check goes after we have calculated the length, because that calculation can throw
1697 // errors that are not type errors and at least the tests expect those rather than type errors.
1698 if (!C || !C->isConstructor())
1699 return scope.engine->throwTypeError();
1700
1701 ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
1702 CHECK_EXCEPTION(); // symbol_iterator can throw.
1703 if (!iterator) {
1704 return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
1705 }
1706
1708 ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(int(iterableLength))));
1709 a = C->callAsConstructor(ctorArgument, 1);
1711
1712 // We check exceptions above, and only after doing so, check the array's validity after construction.
1713 if (!::validateTypedArray(a) || (a->getLength() < iterableLength))
1714 return scope.engine->throwTypeError();
1715
1716
1717 // The loop below traverses the iterator, and puts elements into the created array.
1718 ScopedValue mappedValue(scope, Value::undefinedValue());
1719 for (qint64 k = 0; k < iterableLength; ++k) {
1720 done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
1721 if (scope.hasException())
1722 return Runtime::IteratorClose::call(scope.engine, iterator);
1723
1724 if (mapfn) {
1725 mapArguments[0] = *nextValue;
1726 mapArguments[1] = Value::fromDouble(k);
1727 mappedValue = mapfn->call(thisArg, mapArguments, 2);
1728 if (scope.hasException())
1729 return Runtime::IteratorClose::call(scope.engine, iterator);
1730 } else {
1731 mappedValue = *nextValue;
1732 }
1733
1734 a->put(k, mappedValue);
1735 if (scope.hasException())
1736 return Runtime::IteratorClose::call(scope.engine, iterator);
1737 }
1738 return a.asReturnedValue();
1739 } else {
1740 // Array-like fallback. We request elements by index, and put them into the created array.
1741 ScopedObject arrayLike(scope, argv[0].toObject(scope.engine));
1742 if (!arrayLike)
1743 return scope.engine->throwTypeError(QString::fromLatin1("Cannot convert %1 to object").arg(argv[0].toQStringNoThrow()));
1744
1745 int len = arrayLike->getLength();
1747
1748 // Getting the length may throw, and must do so before we check the constructor validity.
1749 if (!C || !C->isConstructor())
1750 return scope.engine->throwTypeError();
1751
1753 ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(len)));
1754 a = C->callAsConstructor(ctorArgument, 1);
1756
1757 // We check exceptions above, and only after doing so, check the array's validity after construction.
1758 if (!::validateTypedArray(a) || (a->getLength() < len))
1759 return scope.engine->throwTypeError();
1760
1761 ScopedValue mappedValue(scope, Value::undefinedValue());
1762 ScopedValue kValue(scope);
1763 for (int k = 0; k < len; ++k) {
1764 kValue = arrayLike->get(k);
1766
1767 if (mapfn) {
1768 mapArguments[0] = kValue;
1769 mapArguments[1] = Value::fromDouble(k);
1770 mappedValue = mapfn->call(thisArg, mapArguments, 2);
1772 } else {
1773 mappedValue = kValue;
1774 }
1775
1776 a->put(k, mappedValue);
1778 }
1779 return a.asReturnedValue();
1780 }
1781}
1782
1784{
1785 Scope scope(engine);
1786 ctor->defineReadonlyProperty(engine->id_prototype(), *this);
1787 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
1788 ScopedString s(scope, engine->newString(QStringLiteral("TypedArray")));
1789 ctor->defineReadonlyConfigurableProperty(engine->id_name(), s);
1790 s = scope.engine->newString(QStringLiteral("of"));
1791 ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_of);
1792 s = scope.engine->newString(QStringLiteral("from"));
1793 ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_from, 1);
1794 ctor->addSymbolSpecies();
1795
1796 defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
1797 defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
1798 defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr);
1800
1801 defineDefaultProperty(QStringLiteral("copyWithin"), method_copyWithin, 2);
1802 defineDefaultProperty(QStringLiteral("entries"), method_entries, 0);
1803 defineDefaultProperty(QStringLiteral("every"), method_every, 1);
1804 defineDefaultProperty(QStringLiteral("fill"), method_fill, 1);
1805 defineDefaultProperty(QStringLiteral("filter"), method_filter, 1);
1806 defineDefaultProperty(QStringLiteral("find"), method_find, 1);
1807 defineDefaultProperty(QStringLiteral("findIndex"), method_findIndex, 1);
1808 defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
1809 defineDefaultProperty(QStringLiteral("includes"), method_includes, 1);
1810 defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
1811 defineDefaultProperty(QStringLiteral("join"), method_join, 1);
1812 defineDefaultProperty(QStringLiteral("keys"), method_keys, 0);
1813 defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
1814 defineDefaultProperty(QStringLiteral("map"), method_map, 1);
1815 defineDefaultProperty(QStringLiteral("reduce"), method_reduce, 1);
1816 defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1);
1817 defineDefaultProperty(QStringLiteral("reverse"), method_reverse, 0);
1818 defineDefaultProperty(QStringLiteral("some"), method_some, 1);
1819 defineDefaultProperty(QStringLiteral("set"), method_set, 1);
1820 defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
1821 defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 2);
1822 defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString, 0);
1825
1826 ScopedString valuesString(scope, engine->newIdentifier(QStringLiteral("values")));
1827 ScopedObject values(scope, FunctionObject::createBuiltinFunction(engine, valuesString, method_values, 0));
1830
1831 defineAccessorProperty(engine->symbol_toStringTag(), method_get_toStringTag, nullptr);
1832}
Definition main.cpp:8
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
ObjectType::Data * allocObject(Heap::InternalClass *ic, Args &&... args)
Definition qv4mm_p.h:282
QJSValue expected
Definition qjsengine.cpp:12
QSet< QString >::iterator it
QList< QVariant > arguments
short next
Definition keywords.cpp:445
@ NTypedArrayTypes
Scoped< FunctionObject > ScopedFunctionObject
quint64 ReturnedValue
static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
@ KeyValueIteratorKind
@ ValueIteratorKind
@ KeyIteratorKind
Scoped< String > ScopedString
@ Attr_NotConfigurable
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:108
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define forever
Definition qforeach.h:78
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
Definition qnumeric.h:182
GLenum GLsizei GLsizei GLint * values
[15]
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum src
GLenum GLuint buffer
GLenum type
GLenum target
GLuint start
GLenum GLuint GLintptr offset
GLuint name
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLfloat * val
GLenum array
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
unsigned int quint32
Definition qtypes.h:50
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned char quint8
Definition qtypes.h:46
#define THROW_TYPE_ERROR()
#define CHECK_EXCEPTION()
#define RETURN_UNDEFINED()
#define RETURN_RESULT(r)
ReturnedValue atomicAdd(char *data, Value v)
static TypedArray * typedArraySpeciesCreate(Scope &scope, const TypedArray *instance, uint len)
ReturnedValue atomicExchange(char *data, Value v)
ReturnedValue atomicCompareExchange(char *data, Value expected, Value v)
static double toDouble(Value v)
ReturnedValue atomicXor(char *data, Value v)
ReturnedValue typeToValue(T t)
const TypedArrayOperations operations[NTypedArrayTypes]
void write(char *data, Value value)
T valueToType(Value value)
ReturnedValue read(const char *data)
ReturnedValue atomicStore(char *data, Value v)
static bool validateTypedArray(const Object *o)
ReturnedValue atomicLoad(char *data)
ReturnedValue atomicSub(char *data, Value v)
ReturnedValue atomicAnd(char *data, Value v)
static int toInt32(Value v)
ReturnedValue atomicOr(char *data, Value v)
#define DEFINE_OBJECT_VTABLE(classname)
QList< int > list
[14]
gzip write("uncompressed data")
QList< QTreeWidgetItem * > items
QDBusArgument argument
QJSEngine engine
[0]
static T fetchAndOrOrdered(std::atomic< T > &_q_value, typename QAtomicAdditiveType< T >::AdditiveT valueToAdd) noexcept
static T fetchAndSubOrdered(std::atomic< T > &_q_value, typename QAtomicAdditiveType< T >::AdditiveT valueToAdd) noexcept
static bool testAndSetOrdered(std::atomic< T > &_q_value, T expectedValue, T newValue, T *currentValue=nullptr) noexcept
static T fetchAndAddOrdered(std::atomic< T > &_q_value, typename QAtomicAdditiveType< T >::AdditiveT valueToAdd) noexcept
std::atomic< X > Type
static T fetchAndStoreOrdered(std::atomic< T > &_q_value, T newValue) noexcept
static T fetchAndXorOrdered(std::atomic< T > &_q_value, typename QAtomicAdditiveType< T >::AdditiveT valueToAdd) noexcept
static T loadRelaxed(const std::atomic< T > &_q_value) noexcept
static void storeRelaxed(std::atomic< T > &_q_value, T newValue) noexcept
static T fetchAndAndOrdered(std::atomic< T > &_q_value, typename QAtomicAdditiveType< T >::AdditiveT valueToAdd) noexcept
static constexpr ReturnedValue undefined()
MemoryManager * memoryManager
Symbol * symbol_iterator() const
ReturnedValue throwRangeError(const Value &value)
String * id_length() const
Object * arrayPrototype() const
String * id_constructor() const
FunctionObject * typedArrayCtors
String * id_toString() const
String * id_prototype() const
String * id_toLocaleString() const
String * id_name() const
Symbol * symbol_toStringTag() const
Heap::String * newString(char16_t c)
Heap::String * newIdentifier(const QString &text)
Object * intrinsicTypedArrayPrototype() const
FunctionObject * intrinsicTypedArrayCtor() const
Object * typedArrayPrototype
Heap::Object * newArrayIteratorObject(Object *o)
Heap::ArrayBuffer * newArrayBuffer(const QByteArray &array)
ReturnedValue throwTypeError()
Heap::InternalClass * newInternalClass(const VTable *vtable, Object *prototype)
static Heap::FunctionObject * createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount)
ReturnedValue protoProperty() const
ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget=nullptr) const
ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const
ReturnedValue asReturnedValue() const
Definition qv4value_p.h:342
void init(ExecutionEngine *engine, TypedArray::Type t)
void init(TypedArray::Type t)
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_find(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_filter(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_lastIndexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_buffer(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_length(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_reverse(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_reduce(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_includes(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_map(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_slice(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_reduceRight(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_findIndex(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_indexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_join(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_some(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_byteLength(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_byteOffset(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_get_toStringTag(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_subarray(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_toLocaleString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_copyWithin(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_every(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_fill(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
void init(ExecutionEngine *engine, IntrinsicTypedArrayCtor *ctor)
ExecutionEngine * engine() const
PropertyKey next(const Object *o, Property *pd=nullptr, PropertyAttributes *attrs=nullptr) override
void defineDefaultProperty(StringOrSymbol *name, const Value &value, PropertyAttributes attributes=Attr_Data|Attr_NotEnumerable)
void defineAccessorProperty(const QString &name, VTable::Call getter, VTable::Call setter)
ArrayData::Type arrayType() const
const FunctionObject * speciesConstructor(Scope &scope, const FunctionObject *defaultConstructor) const
bool setPrototypeOf(const Object *p)
void defineReadonlyProperty(const QString &name, const Value &value)
ReturnedValue get(StringOrSymbol *name, bool *hasProperty=nullptr, const Value *receiver=nullptr) const
static PropertyKey fromArrayIndex(uint idx)
static Bool strictEqual(const Value &x, const Value &y)
static ReturnedValue call(ExecutionEngine *, const Value &, int)
static ReturnedValue call(ExecutionEngine *, const Value &)
static ReturnedValue call(ExecutionEngine *, const Value &, Value *)
Value * alloc(qint64 nValues) const =delete
bool hasException() const
ExecutionEngine * engine
constexpr ReturnedValue asReturnedValue() const
QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value() const
QV4_NEARLY_ALWAYS_INLINE constexpr void setRawValue(quint64 raw)
bool isUndefined() const
PropertyKey toPropertyKey() const
static constexpr TypedArrayOperations create(const char *name)
ReturnedValue(* Read)(const char *data)
void(* Write)(char *data, Value value)
static constexpr TypedArrayOperations createWithAtomics(const char *name)
static Heap::TypedArray * create(QV4::ExecutionEngine *e, Heap::TypedArray::Type t)
Heap::TypedArray::Type arrayType() const noexcept
static constexpr VTable::DefineOwnProperty virtualDefineOwnProperty
static constexpr VTable::OwnPropertyKeys virtualOwnPropertyKeys
static constexpr VTable::GetOwnProperty virtualGetOwnProperty
static constexpr VTable::CallAsConstructor virtualCallAsConstructor
static constexpr VTable::Call virtualCall
static constexpr VTable::Get virtualGet
static constexpr VTable::HasProperty virtualHasProperty
static constexpr VTable::Put virtualPut
static constexpr Value fromInt32(int i)
Definition qv4value_p.h:187
bool isFunctionObject() const
Definition qv4value_p.h:309
bool toBoolean() const
Definition qv4value_p.h:97
static constexpr Value undefinedValue()
Definition qv4value_p.h:191
static Value fromDouble(double d)
Definition qv4value_p.h:199
double toNumber() const
Definition qv4value_p.h:323
static constexpr Value fromReturnedValue(ReturnedValue val)
Definition qv4value_p.h:165
const T * as() const
Definition qv4value_p.h:132
QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const
Definition qv4value_p.h:80
QString toQStringNoThrow() const
Definition qv4value.cpp:122
double toInteger() const
Definition qv4value_p.h:394
Heap::Object * toObject(ExecutionEngine *e) const
Definition qv4value_p.h:122
bool isObject() const
Definition qv4value_p.h:302
Definition moc.h:23
~TypedArrayOwnPropertyKeyIterator() override=default
PropertyKey next(const Object *o, Property *pd=nullptr, PropertyAttributes *attrs=nullptr) override