aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-05-17 15:50:06 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-06-02 02:42:51 +0200
commite3e8008ec325bdc690fd9600025d66860cac5e62 (patch)
treee82ab867c272e042afc44c627a6f861c2a306418 /src
parent7bfbd706b56c426e2683e519543b56426310520f (diff)
Allow retrieval of sequences from QJSValue
As we can store sequence types in QJSValue, we should be able to retrieve them, too. Move the declaration of the QV4::Sequence struct into a header to make it less of a hassle to identify sequences. Change-Id: I3e45bfe193c669107f90cd6c502765c0c9f60fb0 Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp45
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp9
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp776
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h62
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp4
-rw-r--r--src/qmlworkerscript/qv4serialize.cpp37
6 files changed, 481 insertions, 452 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 6ace973124..81da5162a9 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1568,8 +1568,8 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMet
return v->toVariant();
} else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
return l->toVariant();
- } else if (object->isListType()) {
- return QV4::SequencePrototype::toVariant(object);
+ } else if (QV4::Sequence *s = object->as<QV4::Sequence>()) {
+ return QV4::SequencePrototype::toVariant(s);
}
}
@@ -2462,28 +2462,24 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
;
}
- {
- if (metaType.flags() & QMetaType::IsEnumeration) {
- *reinterpret_cast<int *>(data) = value.toInt32();
- return true;
- }
+ if (metaType.flags() & QMetaType::IsEnumeration) {
+ *reinterpret_cast<int *>(data) = value.toInt32();
+ return true;
+ }
- if (metaType == QMetaType::fromType<QQmlListReference>()) {
- if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
- *reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference();
- return true;
- }
+ if (metaType == QMetaType::fromType<QQmlListReference>()) {
+ if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
+ *reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference();
+ return true;
}
}
- {
- if (const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>()) {
- const QMetaType valueType = vtw->type();
- if (valueType == metaType)
- return vtw->toGadget(data);
- if (QMetaType::canConvert(valueType, metaType))
- return QMetaType::convert(valueType, vtw->d()->gadgetPtr(), metaType, data);
- }
+ if (const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>()) {
+ const QMetaType valueType = vtw->type();
+ if (valueType == metaType)
+ return vtw->toGadget(data);
+ if (QMetaType::canConvert(valueType, metaType))
+ return QMetaType::convert(valueType, vtw->d()->gadgetPtr(), metaType, data);
}
// Try to use magic; for compatibility with qjsvalue_cast.
@@ -2547,6 +2543,15 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
}
}
+ if (const QV4::Sequence *sequence = value.as<Sequence>()) {
+ const QVariant result = QV4::SequencePrototype::toVariant(sequence);
+ if (result.metaType() == metaType) {
+ metaType.destruct(data);
+ metaType.construct(data, result.constData());
+ return true;
+ }
+ }
+
return false;
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 3d5371b7e0..490cf1be2d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1543,8 +1543,8 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
}
}
- if (auto sequenceMetaType = SequencePrototype::metaTypeForSequence(obj); sequenceMetaType.isValid()) {
- if (sequenceMetaType == conversionMetaType)
+ if (const Sequence *sequence = obj->as<Sequence>()) {
+ if (SequencePrototype::metaTypeForSequence(sequence) == conversionMetaType)
return 1;
else
return 10;
@@ -1888,10 +1888,9 @@ void CallArgument::initAsType(QMetaType metaType)
template <class T, class M>
bool CallArgument::fromContainerValue(const Value &value, M CallArgument::*member)
{
- const Object *object = value.as<Object>();
- if (object && object->isListType()) {
+ if (const Sequence *sequence = value.as<Sequence>()) {
if (T* ptr = static_cast<T *>(SequencePrototype::getRawContainerPtr(
- object, QMetaType(type)))) {
+ sequence, QMetaType(type)))) {
(this->*member) = ptr;
return true;
}
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index c374a9f3cf..fa7bb9d3dd 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -55,7 +55,34 @@
QT_BEGIN_NAMESPACE
-using namespace QV4;
+namespace QV4 {
+
+DEFINE_OBJECT_VTABLE(Sequence);
+
+static const QMetaSequence *metaSequence(const Heap::Sequence *p)
+{
+ return p->typePrivate->extraData.ld;
+}
+
+template<typename Compare>
+void sortSequence(Sequence *sequence, const Compare &compare)
+{
+ const auto *p = sequence->d();
+ const auto *m = metaSequence(p);
+
+ QSequentialIterable iterable(*m, p->typePrivate->listId, p->container);
+ if (iterable.canRandomAccessIterate()) {
+ std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
+ QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
+ compare);
+ } else if (iterable.canReverseIterate()) {
+ std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()),
+ QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()),
+ compare);
+ } else {
+ qWarning() << "Container has no suitable iterator for sorting";
+ }
+}
// helper function to generate valid warnings if errors occur during sequence operations.
static void generateWarning(QV4::ExecutionEngine *v4, const QString& description)
@@ -73,468 +100,413 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
QQmlEnginePrivate::warning(engine, retn);
}
-namespace QV4 {
+struct SequenceOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
+{
+ ~SequenceOwnPropertyKeyIterator() override = default;
+ PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override
+ {
+ const Sequence *s = static_cast<const Sequence *>(o);
+
+ if (s->d()->isReference) {
+ if (!s->d()->object)
+ return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
+ s->loadReference();
+ }
-namespace Heap {
+ if (arrayIndex < quint32(s->size())) {
+ uint index = arrayIndex;
+ ++arrayIndex;
+ if (attrs)
+ *attrs = QV4::Attr_Data;
+ if (pd)
+ pd->value = s->engine()->fromVariant(s->at(index));
+ return PropertyKey::fromArrayIndex(index);
+ }
-struct QV4Sequence : Object {
- void init(const QQmlType &qmlType, const void *container);
- void init(QObject *object, int propertyIndex, const QQmlType &qmlType, bool readOnly);
- void destroy() {
- typePrivate->listId.destroy(container);
- QQmlType::derefHandle(typePrivate);
- object.destroy();
- Object::destroy();
+ return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
}
+};
+
+struct SequenceCompareFunctor
+{
+ SequenceCompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
+ : m_v4(v4), m_compareFn(&compareFn)
+ {}
- mutable void *container;
- const QQmlTypePrivate *typePrivate;
- QV4QPointer<QObject> object;
- int propertyIndex;
- bool isReference : 1;
- bool isReadOnly : 1;
+ bool operator()(const QVariant &lhs, const QVariant &rhs)
+ {
+ QV4::Scope scope(m_v4);
+ ScopedFunctionObject compare(scope, m_compareFn);
+ if (!compare)
+ return m_v4->throwTypeError();
+ Value *argv = scope.alloc(2);
+ argv[0] = m_v4->fromVariant(lhs);
+ argv[1] = m_v4->fromVariant(rhs);
+ QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
+ if (scope.hasException())
+ return false;
+ return result->toNumber() < 0;
+ }
+
+private:
+ QV4::ExecutionEngine *m_v4;
+ const QV4::Value *m_compareFn;
};
-}
+struct SequenceDefaultCompareFunctor
+{
+ bool operator()(const QVariant &lhs, const QVariant &rhs)
+ {
+ return lhs.toString() < rhs.toString();
+ }
+};
-static const QMetaSequence *meta(const Heap::QV4Sequence *p)
+void Heap::Sequence::init(const QQmlType &qmlType, const void *container)
{
- return p->typePrivate->extraData.ld;
+ Object::init();
+
+ Q_ASSERT(qmlType.isSequentialContainer());
+ typePrivate = qmlType.priv();
+ QQmlType::refHandle(typePrivate);
+
+ this->container = typePrivate->listId.create(container);
+ propertyIndex = -1;
+ isReference = false;
+ isReadOnly = false;
+ object.init();
+
+ QV4::Scope scope(internalClass->engine);
+ QV4::Scoped<QV4::Sequence> o(scope, this);
+ o->setArrayType(Heap::ArrayData::Custom);
}
-struct QV4Sequence : public QV4::Object
+void Heap::Sequence::init(
+ QObject *object, int propertyIndex, const QQmlType &qmlType, bool readOnly)
{
- V4_OBJECT2(QV4Sequence, QV4::Object)
- Q_MANAGED_TYPE(V4Sequence)
- V4_PROTOTYPE(sequencePrototype)
- V4_NEEDS_DESTROY
-public:
+ Object::init();
- static const QMetaSequence *metaSequence(const Heap::QV4Sequence *p)
- {
- return p->typePrivate->extraData.ld;
- }
+ Q_ASSERT(qmlType.isSequentialContainer());
+ typePrivate = qmlType.priv();
+ QQmlType::refHandle(typePrivate);
+ container = QMetaType(typePrivate->listId).create();
+ this->propertyIndex = propertyIndex;
+ isReference = true;
+ this->isReadOnly = readOnly;
+ this->object.init(object);
+ QV4::Scope scope(internalClass->engine);
+ QV4::Scoped<QV4::Sequence> o(scope, this);
+ o->setArrayType(Heap::ArrayData::Custom);
+ o->loadReference();
+}
- static const QMetaType valueMetaType(const Heap::QV4Sequence *p)
- {
- return p->typePrivate->typeId;
- }
+void Heap::Sequence::destroy()
+{
+ typePrivate->listId.destroy(container);
+ QQmlType::derefHandle(typePrivate);
+ object.destroy();
+ Object::destroy();
+}
- qsizetype size() const
- {
- const auto *p = d();
- return metaSequence(p)->size(p->container);
- }
+const QMetaType Sequence::valueMetaType(const Heap::Sequence *p)
+{
+ return p->typePrivate->typeId;
+}
- QVariant at(int index) const
- {
- const auto *p = d();
- const QMetaType v = valueMetaType(p);
- QVariant result;
- if (v == QMetaType::fromType<QVariant>()) {
- metaSequence(p)->valueAtIndex(p->container, index, &result);
- } else {
- result = QVariant(v);
- metaSequence(p)->valueAtIndex(p->container, index, result.data());
- }
- return result;
- }
+qsizetype Sequence::size() const
+{
+ const auto *p = d();
+ return metaSequence(p)->size(p->container);
+}
- void append(const QVariant &item)
- {
- const auto *p = d();
- const auto *m = metaSequence(p);
- const QMetaType v = valueMetaType(p);
- if (item.metaType() == v) {
- m->addValueAtEnd(p->container, item.constData());
- } else if (v == QMetaType::fromType<QVariant>()) {
- m->addValueAtEnd(p->container, &item);
- } else {
- QVariant converted = item;
- if (!converted.convert(v))
- converted = QVariant(v);
- m->addValueAtEnd(p->container, converted.constData());
- }
+QVariant Sequence::at(int index) const
+{
+ const auto *p = d();
+ const QMetaType v = valueMetaType(p);
+ QVariant result;
+ if (v == QMetaType::fromType<QVariant>()) {
+ metaSequence(p)->valueAtIndex(p->container, index, &result);
+ } else {
+ result = QVariant(v);
+ metaSequence(p)->valueAtIndex(p->container, index, result.data());
}
+ return result;
+}
- void replace(int index, const QVariant &item)
- {
- const auto *p = d();
- const auto *m = metaSequence(p);
- const QMetaType v = valueMetaType(p);
- if (item.metaType() == v) {
- m->setValueAtIndex(p->container, index, item.constData());
- } else if (v == QMetaType::fromType<QVariant>()) {
- m->setValueAtIndex(p->container, index, &item);
- } else {
- QVariant converted = item;
- if (!converted.convert(v))
- converted = QVariant(v);
- m->setValueAtIndex(p->container, index, converted.constData());
- }
+void Sequence::append(const QVariant &item)
+{
+ const auto *p = d();
+ const auto *m = metaSequence(p);
+ const QMetaType v = valueMetaType(p);
+ if (item.metaType() == v) {
+ m->addValueAtEnd(p->container, item.constData());
+ } else if (v == QMetaType::fromType<QVariant>()) {
+ m->addValueAtEnd(p->container, &item);
+ } else {
+ QVariant converted = item;
+ if (!converted.convert(v))
+ converted = QVariant(v);
+ m->addValueAtEnd(p->container, converted.constData());
}
+}
- template<typename Compare>
- void sort(const Compare &compare)
- {
- const auto *p = d();
- const auto *m = metaSequence(p);
-
- QSequentialIterable iterable(*m, p->typePrivate->listId, p->container);
- if (iterable.canRandomAccessIterate()) {
- std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
- QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
- compare);
- } else if (iterable.canReverseIterate()) {
- std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()),
- QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()),
- compare);
- } else {
- qWarning() << "Container has no suitable iterator for sorting";
- }
+void Sequence::replace(int index, const QVariant &item)
+{
+ const auto *p = d();
+ const auto *m = metaSequence(p);
+ const QMetaType v = valueMetaType(p);
+ if (item.metaType() == v) {
+ m->setValueAtIndex(p->container, index, item.constData());
+ } else if (v == QMetaType::fromType<QVariant>()) {
+ m->setValueAtIndex(p->container, index, &item);
+ } else {
+ QVariant converted = item;
+ if (!converted.convert(v))
+ converted = QVariant(v);
+ m->setValueAtIndex(p->container, index, converted.constData());
}
+}
- void removeLast(int num)
- {
- const auto *p = d();
- const auto *m = metaSequence(p);
-
- if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) {
- void *i = m->end(p->container);
- m->advanceIterator(i, -num);
- void *j = m->end(p->container);
- m->eraseRangeAtIterator(p->container, i, j);
- m->destroyIterator(i);
- m->destroyIterator(j);
- } else {
- for (int i = 0; i < num; ++i)
- m->removeValueAtEnd(p->container);
- }
+void Sequence::removeLast(int num)
+{
+ const auto *p = d();
+ const auto *m = metaSequence(p);
+
+ if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) {
+ void *i = m->end(p->container);
+ m->advanceIterator(i, -num);
+ void *j = m->end(p->container);
+ m->eraseRangeAtIterator(p->container, i, j);
+ m->destroyIterator(i);
+ m->destroyIterator(j);
+ } else {
+ for (int i = 0; i < num; ++i)
+ m->removeValueAtEnd(p->container);
}
+}
- QVariant toVariant()
- {
- const auto *p = d();
- return QVariant(p->typePrivate->listId, p->container);
- }
+QVariant Sequence::toVariant() const
+{
+ const auto *p = d();
+ return QVariant(p->typePrivate->listId, p->container);
+}
- // ### Qt 7 use qsizetype instead.
- QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const
- {
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX) {
- generateWarning(engine(), QLatin1String("Index out of range during indexed get"));
+ReturnedValue Sequence::containerGetIndexed(uint index, bool *hasProperty) const
+{
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX) {
+ generateWarning(engine(), QLatin1String("Index out of range during indexed get"));
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+ if (d()->isReference) {
+ if (!d()->object) {
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
- if (d()->isReference) {
- if (!d()->object) {
- if (hasProperty)
- *hasProperty = false;
- return Encode::undefined();
- }
- loadReference();
- }
- if (index < quint32(size())) {
- if (hasProperty)
- *hasProperty = true;
- return engine()->fromVariant(at(index));
- }
+ loadReference();
+ }
+ if (index < quint32(size())) {
if (hasProperty)
- *hasProperty = false;
- return Encode::undefined();
+ *hasProperty = true;
+ return engine()->fromVariant(at(index));
}
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+}
- // ### Qt 7 use qsizetype instead.
- bool containerPutIndexed(uint index, const QV4::Value &value)
- {
- if (internalClass()->engine->hasException)
- return false;
+bool Sequence::containerPutIndexed(uint index, const Value &value)
+{
+ if (internalClass()->engine->hasException)
+ return false;
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX) {
- generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
- return false;
- }
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX) {
+ generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
+ return false;
+ }
- if (d()->isReadOnly) {
- engine()->throwTypeError(QLatin1String("Cannot insert into a readonly container"));
+ if (d()->isReadOnly) {
+ engine()->throwTypeError(QLatin1String("Cannot insert into a readonly container"));
+ return false;
+ }
+
+ if (d()->isReference) {
+ if (!d()->object)
return false;
- }
+ loadReference();
+ }
- if (d()->isReference) {
- if (!d()->object)
- return false;
- loadReference();
- }
+ quint32 count = quint32(size());
+ const QMetaType valueType = valueMetaType(d());
+ const QVariant element = engine()->toVariant(value, valueType, false);
- quint32 count = quint32(size());
- const QMetaType valueType = valueMetaType(d());
- const QVariant element = engine()->toVariant(value, valueType, false);
-
- if (index == count) {
- append(element);
- } else if (index < count) {
- replace(index, element);
- } else {
- /* according to ECMA262r3 we need to insert */
- /* the value at the given index, increasing length to index+1. */
- while (index > count++) {
- append(valueType == QMetaType::fromType<QVariant>()
- ? QVariant()
- : QVariant(valueType));
- }
- append(element);
+ if (index == count) {
+ append(element);
+ } else if (index < count) {
+ replace(index, element);
+ } else {
+ /* according to ECMA262r3 we need to insert */
+ /* the value at the given index, increasing length to index+1. */
+ while (index > count++) {
+ append(valueType == QMetaType::fromType<QVariant>()
+ ? QVariant()
+ : QVariant(valueType));
}
-
- if (d()->isReference)
- storeReference();
- return true;
+ append(element);
}
- QV4::PropertyAttributes containerQueryIndexed(uint index) const
- {
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX) {
- generateWarning(engine(), QLatin1String("Index out of range during indexed query"));
+ if (d()->isReference)
+ storeReference();
+ return true;
+}
+
+PropertyAttributes Sequence::containerQueryIndexed(uint index) const
+{
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX) {
+ generateWarning(engine(), QLatin1String("Index out of range during indexed query"));
+ return QV4::Attr_Invalid;
+ }
+ if (d()->isReference) {
+ if (!d()->object)
return QV4::Attr_Invalid;
- }
- if (d()->isReference) {
- if (!d()->object)
- return QV4::Attr_Invalid;
- loadReference();
- }
- return (index < quint32(size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ loadReference();
}
+ return (index < quint32(size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
+}
- struct OwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
- {
- ~OwnPropertyKeyIterator() override = default;
- PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override
- {
- const QV4Sequence *s = static_cast<const QV4Sequence *>(o);
-
- if (s->d()->isReference) {
- if (!s->d()->object)
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
- s->loadReference();
- }
-
- if (arrayIndex < quint32(s->size())) {
- uint index = arrayIndex;
- ++arrayIndex;
- if (attrs)
- *attrs = QV4::Attr_Data;
- if (pd)
- pd->value = s->engine()->fromVariant(s->at(index));
- return PropertyKey::fromArrayIndex(index);
- }
-
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
- }
- };
-
- static OwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *m, Value *target)
- {
- *target = *m;
- return new OwnPropertyKeyIterator;
- }
+SequenceOwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *m, Value *target)
+{
+ *target = *m;
+ return new SequenceOwnPropertyKeyIterator;
+}
- bool containerDeleteIndexedProperty(uint index)
- {
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX)
- return false;
- if (d()->isReadOnly)
+bool Sequence::containerDeleteIndexedProperty(uint index)
+{
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX)
+ return false;
+ if (d()->isReadOnly)
+ return false;
+ if (d()->isReference) {
+ if (!d()->object)
return false;
- if (d()->isReference) {
- if (!d()->object)
- return false;
- loadReference();
- }
+ loadReference();
+ }
- if (index >= quint32(size()))
- return false;
+ if (index >= quint32(size()))
+ return false;
- /* according to ECMA262r3 it should be Undefined, */
- /* but we cannot, so we insert a default-value instead. */
- replace(index, QVariant());
+ /* according to ECMA262r3 it should be Undefined, */
+ /* but we cannot, so we insert a default-value instead. */
+ replace(index, QVariant());
- if (d()->isReference)
- storeReference();
+ if (d()->isReference)
+ storeReference();
- return true;
- }
+ return true;
+}
- bool containerIsEqualTo(Managed *other)
- {
- if (!other)
- return false;
- QV4Sequence *otherSequence = other->as<QV4Sequence>();
- if (!otherSequence)
- return false;
- if (d()->isReference && otherSequence->d()->isReference) {
- return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex;
- } else if (!d()->isReference && !otherSequence->d()->isReference) {
- return this == otherSequence;
- }
+bool Sequence::containerIsEqualTo(Managed *other)
+{
+ if (!other)
+ return false;
+ Sequence *otherSequence = other->as<Sequence>();
+ if (!otherSequence)
return false;
+ if (d()->isReference && otherSequence->d()->isReference) {
+ return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex;
+ } else if (!d()->isReference && !otherSequence->d()->isReference) {
+ return this == otherSequence;
}
+ return false;
+}
- struct DefaultCompareFunctor
- {
- bool operator()(const QVariant &lhs, const QVariant &rhs)
- {
- return lhs.toString() < rhs.toString();
- }
- };
-
- struct CompareFunctor
- {
- CompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
- : m_v4(v4), m_compareFn(&compareFn)
- {}
-
- bool operator()(const QVariant &lhs, const QVariant &rhs)
- {
- QV4::Scope scope(m_v4);
- ScopedFunctionObject compare(scope, m_compareFn);
- if (!compare)
- return m_v4->throwTypeError();
- Value *argv = scope.alloc(2);
- argv[0] = m_v4->fromVariant(lhs);
- argv[1] = m_v4->fromVariant(rhs);
- QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
- if (scope.hasException())
- return false;
- return result->toNumber() < 0;
- }
-
- private:
- QV4::ExecutionEngine *m_v4;
- const QV4::Value *m_compareFn;
- };
-
- bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
- {
- if (d()->isReadOnly)
+bool Sequence::sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ if (d()->isReadOnly)
+ return false;
+ if (d()->isReference) {
+ if (!d()->object)
return false;
- if (d()->isReference) {
- if (!d()->object)
- return false;
- loadReference();
- }
-
- if (argc == 1 && argv[0].as<FunctionObject>())
- sort(CompareFunctor(f->engine(), argv[0]));
- else
- sort(DefaultCompareFunctor());
-
- if (d()->isReference)
- storeReference();
-
- return true;
+ loadReference();
}
- void* getRawContainerPtr() const
- { return d()->container; }
+ if (argc == 1 && argv[0].as<FunctionObject>())
+ sortSequence(this, SequenceCompareFunctor(f->engine(), argv[0]));
+ else
+ sortSequence(this, SequenceDefaultCompareFunctor());
- void loadReference() const
- {
- Q_ASSERT(d()->object);
- Q_ASSERT(d()->isReference);
- void *a[] = { d()->container, nullptr };
- QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a);
- }
+ if (d()->isReference)
+ storeReference();
- void storeReference()
- {
- Q_ASSERT(d()->object);
- Q_ASSERT(d()->isReference);
- int status = -1;
- QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding;
- void *a[] = { d()->container, nullptr, &status, &flags };
- QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a);
- }
-
- static QV4::ReturnedValue virtualGet(const QV4::Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty)
- {
- if (!id.isArrayIndex())
- return Object::virtualGet(that, id, receiver, hasProperty);
- return static_cast<const QV4Sequence *>(that)->containerGetIndexed(id.asArrayIndex(), hasProperty);
- }
- static bool virtualPut(Managed *that, PropertyKey id, const QV4::Value &value, Value *receiver)
- {
- if (id.isArrayIndex())
- return static_cast<QV4Sequence *>(that)->containerPutIndexed(id.asArrayIndex(), value);
- return Object::virtualPut(that, id, value, receiver);
- }
- static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
- { return static_cast<const QV4Sequence *>(that)->containerQueryIndexed(index); }
- static bool virtualDeleteProperty(QV4::Managed *that, PropertyKey id)
- {
- if (id.isArrayIndex()) {
- uint index = id.asArrayIndex();
- return static_cast<QV4Sequence *>(that)->containerDeleteIndexedProperty(index);
- }
- return Object::virtualDeleteProperty(that, id);
- }
- static bool virtualIsEqualTo(Managed *that, Managed *other)
- { return static_cast<QV4Sequence *>(that)->containerIsEqualTo(other); }
- static QV4::OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target)
- { return static_cast<const QV4Sequence *>(m)->containerOwnPropertyKeys(m, target);}
-};
+ return true;
+}
+void *Sequence::getRawContainerPtr() const
+{ return d()->container; }
-void Heap::QV4Sequence::init(const QQmlType &qmlType, const void *container)
+void Sequence::loadReference() const
{
- Object::init();
-
- Q_ASSERT(qmlType.isSequentialContainer());
- typePrivate = qmlType.priv();
- QQmlType::refHandle(typePrivate);
+ Q_ASSERT(d()->object);
+ Q_ASSERT(d()->isReference);
+ void *a[] = { d()->container, nullptr };
+ QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a);
+}
- this->container = typePrivate->listId.create(container);
- propertyIndex = -1;
- isReference = false;
- isReadOnly = false;
- object.init();
+void Sequence::storeReference()
+{
+ Q_ASSERT(d()->object);
+ Q_ASSERT(d()->isReference);
+ int status = -1;
+ QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding;
+ void *a[] = { d()->container, nullptr, &status, &flags };
+ QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a);
+}
- QV4::Scope scope(internalClass->engine);
- QV4::Scoped<QV4::QV4Sequence> o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
+ReturnedValue Sequence::virtualGet(const Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty)
+{
+ if (!id.isArrayIndex())
+ return Object::virtualGet(that, id, receiver, hasProperty);
+ return static_cast<const Sequence *>(that)->containerGetIndexed(id.asArrayIndex(), hasProperty);
}
-void Heap::QV4Sequence::init(QObject *object, int propertyIndex, const QQmlType &qmlType,
- bool readOnly)
+bool Sequence::virtualPut(Managed *that, PropertyKey id, const Value &value, Value *receiver)
{
- Object::init();
+ if (id.isArrayIndex())
+ return static_cast<Sequence *>(that)->containerPutIndexed(id.asArrayIndex(), value);
+ return Object::virtualPut(that, id, value, receiver);
+}
- Q_ASSERT(qmlType.isSequentialContainer());
- typePrivate = qmlType.priv();
- QQmlType::refHandle(typePrivate);
- container = QMetaType(typePrivate->listId).create();
- this->propertyIndex = propertyIndex;
- isReference = true;
- this->isReadOnly = readOnly;
- this->object.init(object);
- QV4::Scope scope(internalClass->engine);
- QV4::Scoped<QV4::QV4Sequence> o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
- o->loadReference();
+PropertyAttributes Sequence::queryIndexed(const Managed *that, uint index)
+{ return static_cast<const Sequence *>(that)->containerQueryIndexed(index); }
+
+bool Sequence::virtualDeleteProperty(Managed *that, PropertyKey id)
+{
+ if (id.isArrayIndex()) {
+ uint index = id.asArrayIndex();
+ return static_cast<Sequence *>(that)->containerDeleteIndexedProperty(index);
+ }
+ return Object::virtualDeleteProperty(that, id);
}
+bool Sequence::virtualIsEqualTo(Managed *that, Managed *other)
+{
+ return static_cast<Sequence *>(that)->containerIsEqualTo(other);
}
-namespace QV4 {
-DEFINE_OBJECT_VTABLE(QV4Sequence);
+OwnPropertyKeyIterator *Sequence::virtualOwnPropertyKeys(const Object *m, Value *target)
+{
+ return containerOwnPropertyKeys(m, target);
}
static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
QV4::Scope scope(b);
- QV4::Scoped<QV4Sequence> This(scope, thisObject->as<QV4Sequence>());
+ QV4::Scoped<Sequence> This(scope, thisObject->as<Sequence>());
if (!This)
THROW_TYPE_ERROR();
@@ -549,7 +521,7 @@ static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value
static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
QV4::Scope scope(f);
- QV4::Scoped<QV4Sequence> This(scope, thisObject->as<QV4Sequence>());
+ QV4::Scoped<Sequence> This(scope, thisObject->as<Sequence>());
if (!This)
THROW_TYPE_ERROR();
@@ -575,7 +547,7 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value
if (newCount == count) {
RETURN_UNDEFINED();
} else if (newCount > count) {
- const QMetaType valueMetaType = meta(This->d())->valueMetaType();
+ const QMetaType valueMetaType = metaSequence(This->d())->valueMetaType();
/* according to ECMA262r3 we need to insert */
/* undefined values increasing length to newLength. */
/* We cannot, so we insert default-values instead. */
@@ -617,7 +589,7 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu
if (argc >= 2)
return o.asReturnedValue();
- if (auto *s = o->as<QV4Sequence>()) {
+ if (auto *s = o->as<Sequence>()) {
if (!s->sort(b, thisObject, argv, argc))
THROW_TYPE_ERROR();
}
@@ -638,7 +610,7 @@ ReturnedValue SequencePrototype::newSequence(
const QQmlType qmlType = QQmlMetaType::qmlListType(sequenceType);
if (qmlType.isSequentialContainer()) {
*succeeded = true;
- QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>(
+ QV4::ScopedObject obj(scope, engine->memoryManager->allocate<Sequence>(
object, propertyIndex, qmlType, readOnly));
return obj.asReturnedValue();
}
@@ -664,7 +636,7 @@ ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType typ
const QQmlType qmlType = QQmlMetaType::qmlListType(type);
if (qmlType.isSequentialContainer()) {
*succeeded = true;
- QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>(qmlType, data));
+ QV4::ScopedObject obj(scope, engine->memoryManager->allocate<Sequence>(qmlType, data));
return obj.asReturnedValue();
}
@@ -672,10 +644,10 @@ ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType typ
return Encode::undefined();
}
-QVariant SequencePrototype::toVariant(Object *object)
+QVariant SequencePrototype::toVariant(const Sequence *object)
{
Q_ASSERT(object->isListType());
- return object->as<QV4Sequence>()->toVariant();
+ return object->toVariant();
}
QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHint, bool *succeeded)
@@ -721,22 +693,20 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
return QVariant();
}
-void *SequencePrototype::getRawContainerPtr(const Object *object, QMetaType typeHint)
+void *SequencePrototype::getRawContainerPtr(const Sequence *object, QMetaType typeHint)
{
- if (auto *s = object->as<QV4Sequence>()) {
- if (s->d()->typePrivate->listId == typeHint)
- return s->getRawContainerPtr();
- }
+ if (object->d()->typePrivate->listId == typeHint)
+ return object->getRawContainerPtr();
return nullptr;
}
-QMetaType SequencePrototype::metaTypeForSequence(const QV4::Object *object)
+QMetaType SequencePrototype::metaTypeForSequence(const Sequence *object)
{
- if (auto *s = object->as<QV4Sequence>())
- return s->d()->typePrivate->listId;
- return QMetaType();
+ return object->d()->typePrivate->listId;
}
+} // namespace QV4
+
QT_END_NAMESPACE
#include "moc_qv4sequenceobject_p.cpp"
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index ff09ec815c..65ccb32a26 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct Sequence;
struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object
{
V4_PROTOTYPE(arrayPrototype)
@@ -81,10 +82,65 @@ struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object
static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant &v, bool *succeeded);
static ReturnedValue fromData(QV4::ExecutionEngine *engine, QMetaType type, const void *data, bool *succeeded);
- static QMetaType metaTypeForSequence(const Object *object);
- static QVariant toVariant(Object *object);
+ static QMetaType metaTypeForSequence(const Sequence *object);
+ static QVariant toVariant(const Sequence *object);
static QVariant toVariant(const Value &array, QMetaType typeHint, bool *succeeded);
- static void *getRawContainerPtr(const Object *object, QMetaType typeHint);
+ static void *getRawContainerPtr(const Sequence *object, QMetaType typeHint);
+};
+
+namespace Heap {
+
+struct Sequence : Object {
+ void init(const QQmlType &qmlType, const void *container);
+ void init(QObject *object, int propertyIndex, const QQmlType &qmlType, bool readOnly);
+ void destroy();
+
+ mutable void *container;
+ const QQmlTypePrivate *typePrivate;
+ QV4QPointer<QObject> object;
+ int propertyIndex;
+ bool isReference : 1;
+ bool isReadOnly : 1;
+};
+
+}
+
+struct Q_QML_PRIVATE_EXPORT Sequence : public QV4::Object
+{
+ V4_OBJECT2(Sequence, QV4::Object)
+ Q_MANAGED_TYPE(V4Sequence)
+ V4_PROTOTYPE(sequencePrototype)
+ V4_NEEDS_DESTROY
+public:
+ static const QMetaType valueMetaType(const Heap::Sequence *p);
+ static QV4::ReturnedValue virtualGet(
+ const QV4::Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty);
+ static bool virtualPut(Managed *that, PropertyKey id, const QV4::Value &value, Value *receiver);
+ static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index);
+ static bool virtualDeleteProperty(QV4::Managed *that, PropertyKey id);
+ static bool virtualIsEqualTo(Managed *that, Managed *other);
+ static QV4::OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
+
+ qsizetype size() const;
+ QVariant at(int index) const;
+ void append(const QVariant &item);
+ void replace(int index, const QVariant &item);
+ void removeLast(int num);
+ QVariant toVariant() const;
+
+ // ### Qt 7 use qsizetype instead.
+ QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const;
+
+ // ### Qt 7 use qsizetype instead.
+ bool containerPutIndexed(uint index, const QV4::Value &value);
+
+ QV4::PropertyAttributes containerQueryIndexed(uint index) const;
+ bool containerDeleteIndexedProperty(uint index);
+ bool containerIsEqualTo(Managed *other);
+ bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc);
+ void *getRawContainerPtr() const;
+ void loadReference() const;
+ void storeReference();
};
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index cd847903e4..919bbeb572 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -753,7 +753,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
} else if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
// Value type list
QV4::Scope scope(engine);
- QV4::ScopedObject sequence(scope, *(md->data() + id));
+ QV4::Scoped<QV4::Sequence> sequence(scope, *(md->data() + id));
const void *data = sequence
? QV4::SequencePrototype::getRawContainerPtr(sequence, propType)
: nullptr;
@@ -849,7 +849,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
} else if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
// Value type list
QV4::Scope scope(engine);
- QV4::ScopedObject sequence(scope, *(md->data() + id));
+ QV4::Scoped<QV4::Sequence> sequence(scope, *(md->data() + id));
void *data = sequence
? QV4::SequencePrototype::getRawContainerPtr(sequence, propType)
: nullptr;
diff --git a/src/qmlworkerscript/qv4serialize.cpp b/src/qmlworkerscript/qv4serialize.cpp
index b9b4d6aa08..b7ad2a6313 100644
--- a/src/qmlworkerscript/qv4serialize.cpp
+++ b/src/qmlworkerscript/qv4serialize.cpp
@@ -240,28 +240,27 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
}
// No other QObject's are allowed to be sent
push(data, valueheader(WorkerUndefined));
- } else if (const Object *o = v.as<Object>()) {
- if (o->isListType()) {
- // valid sequence. we generate a length (sequence length + 1 for the sequence type)
- uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32();
- uint length = seqLength + 1;
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- reserve(data, sizeof(quint32) + length * sizeof(quint32));
- push(data, valueheader(WorkerSequence, length));
+ } else if (const Sequence *s = v.as<Sequence>()) {
+ // valid sequence. we generate a length (sequence length + 1 for the sequence type)
+ uint seqLength = ScopedValue(scope, s->get(engine->id_length()))->toUInt32();
+ uint length = seqLength + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ reserve(data, sizeof(quint32) + length * sizeof(quint32));
+ push(data, valueheader(WorkerSequence, length));
- // sequence type
- serialize(data, QV4::Value::fromInt32(
- QV4::SequencePrototype::metaTypeForSequence(o).id()), engine);
+ // sequence type
+ serialize(data, QV4::Value::fromInt32(
+ QV4::SequencePrototype::metaTypeForSequence(s).id()), engine);
- ScopedValue val(scope);
- for (uint ii = 0; ii < seqLength; ++ii)
- serialize(data, (val = o->get(ii)), engine); // sequence elements
+ ScopedValue val(scope);
+ for (uint ii = 0; ii < seqLength; ++ii)
+ serialize(data, (val = s->get(ii)), engine); // sequence elements
- return;
- }
+ return;
+ } else if (const Object *o = v.as<Object>()) {
const QVariant variant = engine->toVariant(v, QMetaType::fromType<QUrl>(), false);
if (variant.userType() == QMetaType::QUrl) {
serializeString(data, variant.value<QUrl>().toString(), WorkerUrl);