diff options
Diffstat (limited to 'src/qml/jsruntime/qv4sequenceobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 204 |
1 files changed, 101 insertions, 103 deletions
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 132084705c..cc899428c2 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -27,9 +27,9 @@ static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) { Heap::ReferenceObject::Flags flags = Heap::ReferenceObject::EnforcesLocation; - if (s->d()->typePrivate()->extraData.ld->canSetValueAtIndex()) + if (s->d()->metaSequence().canSetValueAtIndex()) flags |= Heap::ReferenceObject::CanWriteBack; - if (Sequence::valueMetaType(s->d()) == QMetaType::fromType<QVariant>()) + if (s->d()->valueMetaType() == QMetaType::fromType<QVariant>()) flags |= Heap::ReferenceObject::IsVariant; QV4::ScopedValue v(scope, scope.engine->fromVariant( @@ -42,18 +42,12 @@ static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) { return v->asReturnedValue(); } -static const QMetaSequence *metaSequence(const Heap::Sequence *p) -{ - return p->typePrivate()->extraData.ld; -} - template<typename Compare> void sortSequence(Sequence *sequence, const Compare &compare) { - auto *p = sequence->d(); - const auto *m = metaSequence(p); + /* non-const */ Heap::Sequence *p = sequence->d(); - QSequentialIterable iterable(*m, p->typePrivate()->listId, p->storagePointer()); + QSequentialIterable iterable(p->metaSequence(), p->listType(), p->storagePointer()); if (iterable.canRandomAccessIterate()) { std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()), QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()), @@ -148,37 +142,35 @@ struct SequenceDefaultCompareFunctor } }; -void Heap::Sequence::init(const QQmlType &qmlType, const void *container) +void Heap::Sequence::initTypes(QMetaType listType, QMetaSequence metaSequence) { - ReferenceObject::init(nullptr, -1, NoFlag); - - Q_ASSERT(qmlType.isSequentialContainer()); - m_typePrivate = qmlType.priv(); - QQmlType::refHandle(m_typePrivate); - - m_container = m_typePrivate->listId.create(container); - + m_listType = listType.iface(); + Q_ASSERT(m_listType); + m_metaSequence = metaSequence.iface(); + Q_ASSERT(m_metaSequence); QV4::Scope scope(internalClass->engine); QV4::Scoped<QV4::Sequence> o(scope, this); o->setArrayType(Heap::ArrayData::Custom); } +void Heap::Sequence::init(QMetaType listType, QMetaSequence metaSequence, const void *container) +{ + ReferenceObject::init(nullptr, -1, NoFlag); + initTypes(listType, metaSequence); + m_container = listType.create(container); +} + void Heap::Sequence::init( - const QQmlType &qmlType, const void *container, - Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags) + QMetaType listType, QMetaSequence metaSequence, const void *container, + Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags) { ReferenceObject::init(object, propertyIndex, flags); + initTypes(listType, metaSequence); - Q_ASSERT(qmlType.isSequentialContainer()); - m_typePrivate = qmlType.priv(); - QQmlType::refHandle(m_typePrivate); - QV4::Scope scope(internalClass->engine); - QV4::Scoped<QV4::Sequence> o(scope, this); - o->setArrayType(Heap::ArrayData::Custom); - if (CppStackFrame *frame = scope.engine->currentStackFrame) + if (CppStackFrame *frame = internalClass->engine->currentStackFrame) setLocation(frame->v4Function, frame->statementNumber()); if (container) - m_container = QMetaType(m_typePrivate->listId).create(container); + m_container = listType.create(container); else if (flags & EnforcesLocation) QV4::ReferenceObject::readReference(this); } @@ -186,28 +178,27 @@ void Heap::Sequence::init( Heap::Sequence *Heap::Sequence::detached() const { return internalClass->engine->memoryManager->allocate<QV4::Sequence>( - QQmlType(m_typePrivate), m_container); + QMetaType(m_listType), QMetaSequence(m_metaSequence), m_container); } void Heap::Sequence::destroy() { if (m_container) - m_typePrivate->listId.destroy(m_container); - QQmlType::derefHandle(m_typePrivate); + listType().destroy(m_container); ReferenceObject::destroy(); } void *Heap::Sequence::storagePointer() { if (!m_container) - m_container = m_typePrivate->listId.create(); + m_container = listType().create(); return m_container; } bool Heap::Sequence::setVariant(const QVariant &variant) { const QMetaType variantReferenceType = variant.metaType(); - if (variantReferenceType != m_typePrivate->listId) { + if (variantReferenceType != listType()) { // This is a stale reference. That is, the property has been // overwritten with a different type in the meantime. // We need to modify this reference to the updated type, if @@ -215,11 +206,10 @@ bool Heap::Sequence::setVariant(const QVariant &variant) const QQmlType newType = QQmlMetaType::qmlListType(variantReferenceType); if (newType.isSequentialContainer()) { if (m_container) - m_typePrivate->listId.destroy(m_container); - QQmlType::derefHandle(m_typePrivate); - m_typePrivate = newType.priv(); - QQmlType::refHandle(m_typePrivate); - m_container = m_typePrivate->listId.create(variant.constData()); + listType().destroy(m_container); + m_listType = newType.qListTypeId().iface(); + m_metaSequence = newType.listMetaSequence().iface(); + m_container = listType().create(variant.constData()); return true; } else { return false; @@ -235,32 +225,27 @@ bool Heap::Sequence::setVariant(const QVariant &variant) } QVariant Heap::Sequence::toVariant() const { - return QVariant(m_typePrivate->listId, m_container); -} - -const QMetaType Sequence::valueMetaType(const Heap::Sequence *p) -{ - return p->typePrivate()->typeId; + return QVariant(listType(), m_container); } qsizetype Sequence::size() const { const auto *p = d(); Q_ASSERT(p->storagePointer()); // Must readReference() before - return metaSequence(p)->size(p->storagePointer()); + return p->metaSequence().size(p->storagePointer()); } QVariant Sequence::at(qsizetype index) const { const auto *p = d(); Q_ASSERT(p->storagePointer()); // Must readReference() before - const QMetaType v = valueMetaType(p); + const QMetaType v = p->valueMetaType(); QVariant result; if (v == QMetaType::fromType<QVariant>()) { - metaSequence(p)->valueAtIndex(p->storagePointer(), index, &result); + p->metaSequence().valueAtIndex(p->storagePointer(), index, &result); } else { result = QVariant(v); - metaSequence(p)->valueAtIndex(p->storagePointer(), index, result.data()); + p->metaSequence().valueAtIndex(p->storagePointer(), index, result.data()); } return result; } @@ -284,45 +269,45 @@ void convertAndDo(const QVariant &item, const QMetaType v, Action action) void Sequence::append(const QVariant &item) { Heap::Sequence *p = d(); - convertAndDo(item, valueMetaType(p), [p](const void *data) { - metaSequence(p)->addValueAtEnd(p->storagePointer(), data); + convertAndDo(item, p->valueMetaType(), [p](const void *data) { + p->metaSequence().addValueAtEnd(p->storagePointer(), data); }); } void Sequence::append(qsizetype num, const QVariant &item) { Heap::Sequence *p = d(); - convertAndDo(item, valueMetaType(p), [p, num](const void *data) { - const QMetaSequence *m = metaSequence(p); + convertAndDo(item, p->valueMetaType(), [p, num](const void *data) { + const QMetaSequence m = p->metaSequence(); void *container = p->storagePointer(); for (qsizetype i = 0; i < num; ++i) - m->addValueAtEnd(container, data); + m.addValueAtEnd(container, data); }); } void Sequence::replace(qsizetype index, const QVariant &item) { Heap::Sequence *p = d(); - convertAndDo(item, valueMetaType(p), [p, index](const void *data) { - metaSequence(p)->setValueAtIndex(p->storagePointer(), index, data); + convertAndDo(item, p->valueMetaType(), [p, index](const void *data) { + p->metaSequence().setValueAtIndex(p->storagePointer(), index, data); }); } void Sequence::removeLast(qsizetype num) { auto *p = d(); - const auto *m = metaSequence(p); - - if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) { - void *i = m->end(p->storagePointer()); - m->advanceIterator(i, -num); - void *j = m->end(p->storagePointer()); - m->eraseRangeAtIterator(p->storagePointer(), i, j); - m->destroyIterator(i); - m->destroyIterator(j); + const QMetaSequence m = p->metaSequence(); + + if (m.canEraseRangeAtIterator() && m.hasRandomAccessIterator() && num > 1) { + void *i = m.end(p->storagePointer()); + m.advanceIterator(i, -num); + void *j = m.end(p->storagePointer()); + m.eraseRangeAtIterator(p->storagePointer(), i, j); + m.destroyIterator(i); + m.destroyIterator(j); } else { for (int i = 0; i < num; ++i) - m->removeValueAtEnd(p->storagePointer()); + m.removeValueAtEnd(p->storagePointer()); } } @@ -355,7 +340,7 @@ bool Sequence::containerPutIndexed(qsizetype index, const Value &value) return false; const qsizetype count = size(); - const QMetaType valueType = valueMetaType(d()); + const QMetaType valueType = d()->valueMetaType(); const QVariant element = ExecutionEngine::toVariant(value, valueType, false); if (index < 0) @@ -467,6 +452,14 @@ ReturnedValue Sequence::virtualGet(const Managed *that, PropertyKey id, const Va return Object::virtualGet(that, id, receiver, hasProperty); } +qint64 Sequence::virtualGetLength(const Managed *m) +{ + const Sequence *s = static_cast<const Sequence *>(m); + if (s->d()->isReference() && !s->loadReference()) + return 0; + return s->size(); +} + bool Sequence::virtualPut(Managed *that, PropertyKey id, const Value &value, Value *receiver) { if (id.isArrayIndex()) { @@ -510,26 +503,27 @@ int Sequence::virtualMetacall(Object *object, QMetaObject::Call call, int index, switch (call) { case QMetaObject::ReadProperty: { - const QMetaType valueType = valueMetaType(sequence->d()); - if (!sequence->loadReference()) + const QMetaType valueType = sequence->d()->valueMetaType(); + if (sequence->d()->isReference() && !sequence->loadReference()) return 0; - const QMetaSequence *metaSequence = sequence->d()->typePrivate()->extraData.ld; - if (metaSequence->valueMetaType() != valueType) + const QMetaSequence metaSequence = sequence->d()->metaSequence(); + if (metaSequence.valueMetaType() != valueType) return 0; // value metatype is not what the caller expects anymore. const void *storagePointer = sequence->d()->storagePointer(); - if (index < 0 || index >= metaSequence->size(storagePointer)) + if (index < 0 || index >= metaSequence.size(storagePointer)) return 0; - metaSequence->valueAtIndex(storagePointer, index, a[0]); + metaSequence.valueAtIndex(storagePointer, index, a[0]); break; } case QMetaObject::WriteProperty: { void *storagePointer = sequence->d()->storagePointer(); - const QMetaSequence *metaSequence = sequence->d()->typePrivate()->extraData.ld; - if (index < 0 || index >= metaSequence->size(storagePointer)) + const QMetaSequence metaSequence = sequence->d()->metaSequence(); + if (index < 0 || index >= metaSequence.size(storagePointer)) return 0; - metaSequence->setValueAtIndex(storagePointer, index, a[0]); - sequence->storeReference(); + metaSequence.setValueAtIndex(storagePointer, index, a[0]); + if (sequence->d()->isReference()) + sequence->storeReference(); break; } default: @@ -584,7 +578,7 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value if (newCount == count) { RETURN_UNDEFINED(); } else if (newCount > count) { - const QMetaType valueMetaType = metaSequence(This->d())->valueMetaType(); + const QMetaType valueMetaType = This->d()->valueMetaType(); /* according to ECMA262r3 we need to insert */ /* undefined values increasing length to newLength. */ /* We cannot, so we insert default-values instead. */ @@ -634,40 +628,43 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu } ReturnedValue SequencePrototype::newSequence( - QV4::ExecutionEngine *engine, QMetaType sequenceType, const void *data, - Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags) + QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data, + Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags) { // This function is called when the property is a QObject Q_PROPERTY of // the given sequence type. Internally we store a sequence // (as well as object ptr + property index for updated-read and write-back) // and so access/mutate avoids variant conversion. - const QQmlType qmlType = QQmlMetaType::qmlListType(sequenceType); - if (qmlType.isSequentialContainer()) { - return engine->memoryManager->allocate<Sequence>( - qmlType, data, object, propertyIndex, flags)->asReturnedValue(); - } - - return Encode::undefined(); + return engine->memoryManager->allocate<Sequence>( + type, metaSequence, data, object, propertyIndex, flags)->asReturnedValue(); } ReturnedValue SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const QVariant &v) { - return fromData(engine, v.metaType(), v.constData()); + const QMetaType type = v.metaType(); + const QQmlType qmlType = QQmlMetaType::qmlListType(type); + if (qmlType.isSequentialContainer()) + return fromData(engine, type, qmlType.listMetaSequence(), v.constData()); + + QSequentialIterable iterable; + if (QMetaType::convert( + type, v.constData(), QMetaType::fromType<QSequentialIterable>(), &iterable)) { + return fromData(engine, type, iterable.metaContainer(), v.constData()); + } + + return Encode::undefined(); } -ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType type, const void *data) +ReturnedValue SequencePrototype::fromData( + ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data) { // This function is called when assigning a sequence value to a normal JS var // in a JS block. Internally, we store a sequence of the specified type. // Access and mutation is extremely fast since it will not need to modify any // QObject property. - const QQmlType qmlType = QQmlMetaType::qmlListType(type); - if (qmlType.isSequentialContainer()) - return engine->memoryManager->allocate<Sequence>(qmlType, data)->asReturnedValue(); - - return Encode::undefined(); + return engine->memoryManager->allocate<Sequence>(type, metaSequence, data)->asReturnedValue(); } QVariant SequencePrototype::toVariant(const Sequence *object) @@ -684,7 +681,7 @@ QVariant SequencePrototype::toVariant(const Sequence *object) if (!p->hasData()) return QVariant(); - return QVariant(p->typePrivate()->listId, p->storagePointer()); + return QVariant(p->listType(), p->storagePointer()); } QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHint) @@ -698,7 +695,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin const QQmlType type = QQmlMetaType::qmlListType(typeHint); if (type.isSequentialContainer()) { const QQmlTypePrivate *priv = type.priv(); - const QMetaSequence *meta = priv->extraData.ld; + const QMetaSequence *meta = &priv->extraData.sequentialContainerTypeData; const QMetaType containerMetaType(priv->listId); QVariant result(containerMetaType); qint64 length = a->getLength(); @@ -714,18 +711,19 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin } else { const QMetaType originalType = variant.metaType(); if (originalType != valueMetaType) { - QVariant converted(valueMetaType); - if (QQmlValueTypeProvider::createValueType( - variant, valueMetaType, converted.data())) { + const QVariant converted = QQmlValueTypeProvider::createValueType( + variant, valueMetaType); + if (converted.isValid()) { variant = converted; - } else if (!variant.convert(valueMetaType)) { + } else if (!variant.convert(valueMetaType) && originalType.isValid()) { + // If the original type was void, we're converting a "hole" in a sparse + // array. There is no point in warning about that. qWarning().noquote() << QLatin1String("Could not convert array value " "at position %1 from %2 to %3") .arg(QString::number(i), QString::fromUtf8(originalType.name()), QString::fromUtf8(valueMetaType.name())); - variant = converted; } } meta->addValueAtEnd(result.data(), variant.constData()); @@ -739,14 +737,14 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin void *SequencePrototype::getRawContainerPtr(const Sequence *object, QMetaType typeHint) { - if (object->d()->typePrivate()->listId == typeHint) + if (object->d()->listType() == typeHint) return object->getRawContainerPtr(); return nullptr; } QMetaType SequencePrototype::metaTypeForSequence(const Sequence *object) { - return object->d()->typePrivate()->listId; + return object->d()->listType(); } } // namespace QV4 |