diff options
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4argumentsobject.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4argumentsobject_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 72 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 17 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectiterator.cpp | 81 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectiterator_p.h | 22 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent.cpp | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4propertykey_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 68 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 34 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stringobject.cpp | 56 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stringobject_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vtable_p.h | 9 |
15 files changed, 356 insertions, 37 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index cc2cb83b6b..6c1c4a6eea 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -212,3 +212,9 @@ qint64 ArgumentsObject::virtualGetLength(const Managed *m) const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m); return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->toLength(); } + +OwnPropertyKeyIterator *ArgumentsObject::virtualOwnPropertyKeys(const Object *m) +{ + static_cast<ArgumentsObject *>(const_cast<Object *>(m))->fullyCreate(); + return Object::virtualOwnPropertyKeys(m); +} diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 85939071ed..6be1ab923f 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -106,6 +106,7 @@ struct ArgumentsObject: Object { static bool virtualDeleteProperty(Managed *m, PropertyKey id); static PropertyAttributes virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p); static qint64 virtualGetLength(const Managed *m); + static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m); void fullyCreate(); diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index bb7b8086e4..d51b03d90b 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -142,3 +142,8 @@ bool Managed::virtualIsEqualTo(Managed *, Managed *) { return false; } + + +OwnPropertyKeyIterator::~OwnPropertyKeyIterator() +{ +} diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 701c22331d..f4604dbce7 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -408,6 +408,78 @@ void Object::virtualAdvanceIterator(Managed *m, ObjectIterator *it, Value *name, *attrs = PropertyAttributes(); } +PropertyKey ObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +{ + if (arrayIndex != UINT_MAX && o->arrayData()) { + if (!arrayIndex) + arrayNode = o->sparseBegin(); + + // sparse arrays + if (arrayNode) { + while (arrayNode != o->sparseEnd()) { + uint k = arrayNode->key(); + uint pidx = arrayNode->value; + Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>(); + const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx); + arrayNode = arrayNode->nextNode(); + PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; + arrayIndex = k + 1; + if (pd) + pd->copy(p, a); + if (attrs) + *attrs = a; + return PropertyKey::fromArrayIndex(k); + } + arrayNode = nullptr; + arrayIndex = UINT_MAX; + } + // dense arrays + while (arrayIndex < o->d()->arrayData->values.size) { + Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>(); + const Value &val = sa->data(arrayIndex); + PropertyAttributes a = o->arrayData()->attributes(arrayIndex); + int index = arrayIndex; + ++arrayIndex; + if (!val.isEmpty()) { + if (pd) + pd->value = val; + if (attrs) + *attrs = a; + return PropertyKey::fromArrayIndex(index); + } + } + arrayIndex = UINT_MAX; + } + + while (memberIndex < o->internalClass()->size) { + PropertyKey n = o->internalClass()->nameMap.at(memberIndex); + if (!n.isStringOrSymbol()) { + // accessor properties have a dummy entry with n == 0 + ++memberIndex; + continue; + } + + uint index = memberIndex; + PropertyAttributes a = o->internalClass()->propertyData[memberIndex]; + ++memberIndex; + if (pd) { + pd->value = *o->propertyData(index); + if (a.isAccessor()) + pd->set = *o->propertyData(index + Object::SetterOffset); + } + if (attrs) + *attrs = a; + return n; + } + + return PropertyKey::invalid(); +} + +OwnPropertyKeyIterator *Object::virtualOwnPropertyKeys(const Object *) +{ + return new ObjectOwnPropertyKeyIterator; +} + // Section 8.12.3 ReturnedValue Object::internalGet(StringOrSymbol *name, const Value *receiver, bool *hasProperty) const { diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index a9ad926289..3f1eb2d537 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -280,8 +280,8 @@ public: } void initSparseArray(); - SparseArrayNode *sparseBegin() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : nullptr; } - SparseArrayNode *sparseEnd() { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : nullptr; } + SparseArrayNode *sparseBegin() const { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->begin() : nullptr; } + SparseArrayNode *sparseEnd() const { return arrayType() == Heap::ArrayData::Sparse ? d()->arrayData->sparse->end() : nullptr; } inline bool protoHasArray() { Scope scope(engine()); @@ -355,6 +355,8 @@ public: { return vtable()->deleteProperty(this, id); } void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) { vtable()->advanceIterator(this, it, name, index, p, attributes); } + OwnPropertyKeyIterator *ownPropertyKeys() const + { return vtable()->ownPropertyKeys(this); } qint64 getLength() const { return vtable()->getLength(this); } ReturnedValue instanceOf(const Value &var) const { return vtable()->instanceOf(this, var); } @@ -376,6 +378,7 @@ protected: static Heap::Object *virtualGetPrototypeOf(const Managed *); static bool virtualSetPrototypeOf(Managed *, const Object *); static void virtualAdvanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); + static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m); static qint64 virtualGetLength(const Managed *m); static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var); @@ -390,6 +393,16 @@ private: friend struct ObjectPrototype; }; +struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator +{ + uint arrayIndex = 0; + uint memberIndex = 0; + SparseArrayNode *arrayNode = nullptr; + ~ObjectOwnPropertyKeyIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + +}; + namespace Heap { struct BooleanObject : Object { diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 73c09a864a..d4e07e3d77 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -43,6 +43,7 @@ #include "qv4argumentsobject_p.h" #include "qv4string_p.h" #include "qv4iterator_p.h" +#include "qv4propertykey_p.h" using namespace QV4; @@ -51,20 +52,6 @@ void ForInIteratorPrototype::init(ExecutionEngine *) defineDefaultProperty(QStringLiteral("next"), method_next, 0); } -ReturnedValue ForInIteratorPrototype::method_next(const FunctionObject *b, const Value *thisObject, const Value *, int) -{ - const ForInIteratorObject *forIn = thisObject->as<ForInIteratorObject>(); - Q_ASSERT(forIn); - Scope scope(b->engine()); - ScopedValue n(scope, forIn->nextPropertyName()); - bool done = false; - if (n->asReturnedValue() == Encode::null()) { - done = true; - n = Primitive::undefinedValue(); - } - return IteratorPrototype::createIterResultObject(scope.engine, n, done); -} - void ObjectIterator::init(const Object *o) { object->setM(o ? o->m() : nullptr); @@ -200,7 +187,73 @@ DEFINE_OBJECT_VTABLE(ForInIteratorObject); void Heap::ForInIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack) { ForInIteratorObject *o = static_cast<ForInIteratorObject *>(that); + o->object->mark(markStack); o->workArea[0].mark(markStack); o->workArea[1].mark(markStack); Object::markObjects(that, markStack); } + +void Heap::ForInIteratorObject::destroy() +{ + delete iterator; +} + +ReturnedValue ForInIteratorPrototype::method_next(const FunctionObject *b, const Value *thisObject, const Value *, int) +{ + const ForInIteratorObject *forIn = static_cast<const ForInIteratorObject *>(thisObject); + Q_ASSERT(forIn); + Scope scope(b); + + ScopedPropertyKey key(scope, forIn->nextProperty()); + bool done = false; + if (!key->isValid()) + done = true; + ScopedStringOrSymbol s(scope, key->toStringOrSymbol(scope.engine)); + return IteratorPrototype::createIterResultObject(scope.engine, s, done); +} + + +PropertyKey ForInIteratorObject::nextProperty() const +{ + if (!d()->current) + return PropertyKey::invalid(); + + Scope scope(this); + ScopedObject c(scope, d()->current); + ScopedObject o(scope); + ScopedPropertyKey key(scope); + PropertyAttributes attrs; + + while (1) { + while (1) { + key = d()->iterator->next(c, nullptr, &attrs); + if (!key->isValid()) + break; + if (!attrs.isEnumerable() || key->isSymbol()) + continue; + // check the property is not already defined earlier in the proto chain + if (d()->current != d()->object) { + o = d()->object; + bool shadowed = false; + while (o->d() != c->heapObject()) { + if (o->getOwnProperty(key) != Attr_Invalid) { + shadowed = true; + break; + } + o = o->getPrototypeOf(); + } + if (shadowed) + continue; + } + return key; + } + + c = c->getPrototypeOf(); + d()->current.set(scope.engine, c->d()); + if (!c) + break; + delete d()->iterator; + d()->iterator = c->ownPropertyKeys(); + } + return PropertyKey::invalid(); +} diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 1e7000ad1f..20eb918e12 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -111,14 +111,18 @@ private: }; namespace Heap { -struct ForInIteratorObject : Object { + +#define ForInIteratorObjectMembers(class, Member) \ + Member(class, Pointer, Object *, object) \ + Member(class, Pointer, Object *, current) \ + Member(class, NoMark, OwnPropertyKeyIterator *, iterator) + +DECLARE_HEAP_OBJECT(ForInIteratorObject, Object) { void init(QV4::Object *o); - ObjectIterator &it() { return *reinterpret_cast<ObjectIterator*>(&itData); } Value workArea[2]; static void markObjects(Heap::Base *that, MarkStack *markStack); -private: - ObjectIteratorData itData; + void destroy(); }; } @@ -135,16 +139,20 @@ struct ForInIteratorObject: Object { V4_OBJECT2(ForInIteratorObject, Object) Q_MANAGED_TYPE(ForInIterator) V4_PROTOTYPE(forInIteratorPrototype) + V4_NEEDS_DESTROY - ReturnedValue nextPropertyName() const { return d()->it().nextPropertyNameAsString(); } + PropertyKey nextProperty() const; }; inline void Heap::ForInIteratorObject::init(QV4::Object *o) { Object::init(); - it() = ObjectIterator(internalClass->engine, workArea, workArea + 1, o, - ObjectIterator::EnumerableOnly | ObjectIterator::WithProtoChain); + if (!o) + return; + object.set(o->engine(), o->d()); + current.set(o->engine(), o->d()); + iterator = o->ownPropertyKeys(); } diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index f8bc28160e..79c372348f 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -302,6 +302,10 @@ PersistentValue &PersistentValue::operator=(const PersistentValue &other) return *this; val = other.engine()->memoryManager->m_persistentValues->allocate(); } + if (!other.val) { + *val = Encode::undefined(); + return *this; + } Q_ASSERT(engine() == other.engine()); @@ -316,6 +320,10 @@ PersistentValue &PersistentValue::operator=(const WeakValue &other) return *this; val = other.engine()->memoryManager->m_persistentValues->allocate(); } + if (!other.valueRef()) { + *val = Encode::undefined(); + return *this; + } Q_ASSERT(engine() == other.engine()); @@ -379,6 +387,10 @@ WeakValue &WeakValue::operator=(const WeakValue &other) return *this; allocVal(other.engine()); } + if (!other.val) { + *val = Encode::undefined(); + return *this; + } Q_ASSERT(engine() == other.engine()); diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index 14f8e961ea..7134b06c6d 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -130,6 +130,9 @@ public: Q_QML_EXPORT QString toQString() const; Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e); quint64 id() const { return val; } + static PropertyKey fromId(quint64 id) { + PropertyKey key; key.val = id; return key; + } enum FunctionNamePrefix { None, diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index a17de5d94d..61678acdad 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -814,6 +814,74 @@ void QObjectWrapper::virtualAdvanceIterator(Managed *m, ObjectIterator *it, Valu QV4::Object::virtualAdvanceIterator(m, it, name, index, p, attributes); } +struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator +{ + int propertyIndex = 0; + ~QObjectWrapperOwnPropertyKeyIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + +}; + +PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +{ + // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML + static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); + static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); + static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); + + const QObjectWrapper *that = static_cast<const QObjectWrapper*>(o); + + QObject *thatObject = that->d()->object(); + if (thatObject && !QQmlData::wasDeleted(thatObject)) { + const QMetaObject *mo = thatObject->metaObject(); + // These indices don't apply to gadgets, so don't block them. + const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject; + const int propertyCount = mo->propertyCount(); + if (propertyIndex < propertyCount) { + ExecutionEngine *thatEngine = that->engine(); + Scope scope(thatEngine); + const QMetaProperty property = mo->property(propertyIndex); + ScopedString propName(scope, thatEngine->newString(QString::fromUtf8(property.name()))); + ++propertyIndex; + if (attrs) + *attrs= QV4::Attr_Data; + if (pd) { + QQmlPropertyData local; + local.load(property); + pd->value = that->getProperty(thatEngine, thatObject, &local); + } + return propName->toPropertyKey(); + } + const int methodCount = mo->methodCount(); + while (propertyIndex < propertyCount + methodCount) { + Q_ASSERT(propertyIndex >= propertyCount); + int index = propertyIndex - propertyCount; + const QMetaMethod method = mo->method(index); + ++propertyIndex; + if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) + continue; + ExecutionEngine *thatEngine = that->engine(); + Scope scope(thatEngine); + ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name()))); + if (attrs) + *attrs = QV4::Attr_Data; + if (pd) { + QQmlPropertyData local; + local.load(method); + pd->value = that->getProperty(thatEngine, thatObject, &local); + } + return methodName->toPropertyKey(); + } + } + + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); +} + +OwnPropertyKeyIterator *QObjectWrapper::virtualOwnPropertyKeys(const Object *) +{ + return new QObjectWrapperOwnPropertyKeyIterator; +} + namespace QV4 { struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 7843289d33..203bbfa151 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -182,12 +182,11 @@ struct Q_QML_EXPORT QObjectWrapper : public Object void destroyObject(bool lastCall); -protected: - static bool virtualIsEqualTo(Managed *that, Managed *o); - static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true); +protected: static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value); + static bool virtualIsEqualTo(Managed *that, Managed *o); static ReturnedValue create(ExecutionEngine *engine, QObject *object); static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local); @@ -197,6 +196,7 @@ protected: static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); static PropertyAttributes virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p); static void virtualAdvanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); + static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m); static ReturnedValue method_connect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_disconnect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 1ba889ee82..ab05a819c1 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -365,6 +365,38 @@ public: QV4::Object::virtualAdvanceIterator(this, it, name, index, p, attrs); } + struct OwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator + { + ~OwnPropertyKeyIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override + { + const QQmlSequence *s = static_cast<const QQmlSequence *>(o); + + if (s->d()->isReference) { + if (!s->d()->object) + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); + s->loadReference(); + } + + if (arrayIndex < static_cast<uint>(s->d()->container->size())) { + uint index = arrayIndex; + ++arrayIndex; + if (attrs) + *attrs = QV4::Attr_Data; + if (pd) + pd->value = convertElementToValue(s->engine(), s->d()->container->at(index)); + return PropertyKey::fromArrayIndex(index); + } + + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); + } + }; + + static OwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *) + { + return new OwnPropertyKeyIterator; + } + bool containerDeleteIndexedProperty(uint index) { /* Qt containers have int (rather than uint) allowable indexes. */ @@ -589,6 +621,8 @@ public: { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); } static void virtualAdvanceIterator(Managed *that, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, p, attrs); } + static QV4::OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m) + { return static_cast<const QQmlSequence<Container> *>(m)->containerOwnPropertyKeys(m);} }; diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index f2d0d52013..12fed62bcc 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -137,24 +137,58 @@ void StringObject::virtualAdvanceIterator(Managed *m, ObjectIterator *it, Value return Object::virtualAdvanceIterator(m, it, name, index, p, attrs); } + +struct StringObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator +{ + ~StringObjectOwnPropertyKeyIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + +}; + +PropertyKey StringObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +{ + const StringObject *s = static_cast<const StringObject *>(o); + uint slen = s->d()->string->toQString().length(); + if (arrayIndex < slen) { + uint index = arrayIndex; + ++arrayIndex; + if (attrs) + *attrs = Attr_NotConfigurable|Attr_NotWritable; + if (pd) + pd->value = s->getIndex(index); + return PropertyKey::fromArrayIndex(index); + } else if (arrayIndex == slen) { + if (s->arrayData()) { + arrayNode = s->sparseBegin(); + // iterate until we're past the end of the string + while (arrayNode && arrayNode->key() < slen) + arrayNode = arrayNode->nextNode(); + } + } + + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); +} + +OwnPropertyKeyIterator *StringObject::virtualOwnPropertyKeys(const Object *) +{ + return new StringObjectOwnPropertyKeyIterator; +} + PropertyAttributes StringObject::virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p) { PropertyAttributes attributes = Object::virtualGetOwnProperty(m, id, p); if (attributes != Attr_Invalid) return attributes; - Object *o = static_cast<Object *>(m); - if (id.isArrayIndex()) { - uint index = id.asArrayIndex(); - if (o->isStringObject()) { - if (index >= static_cast<const StringObject *>(m)->length()) - return Attr_Invalid; - if (p) - p->value = static_cast<StringObject *>(o)->getIndex(index); - return Attr_NotConfigurable|Attr_NotWritable; - } + StringObject *s = static_cast<StringObject *>(m); + uint slen = s->d()->string->toQString().length(); + uint index = id.asArrayIndex(); + if (index < slen) { + if (p) + p->value = static_cast<StringObject *>(s)->getIndex(index); + return Attr_NotConfigurable|Attr_NotWritable; } - return Attr_Invalid; + return Object::virtualGetOwnProperty(m, id, p); } DEFINE_OBJECT_VTABLE(StringCtor); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 2d37e36b34..4dd114e06a 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -102,6 +102,7 @@ struct StringObject: Object { protected: static bool virtualDeleteProperty(Managed *m, PropertyKey id); static void virtualAdvanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs); + static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m); static PropertyAttributes virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p); }; diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h index b4e868d45d..aff8eb83ac 100644 --- a/src/qml/jsruntime/qv4vtable_p.h +++ b/src/qml/jsruntime/qv4vtable_p.h @@ -56,6 +56,11 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct OwnPropertyKeyIterator { + virtual ~OwnPropertyKeyIterator() = 0; + virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0; +}; + struct VTable { typedef void (*Destroy)(Heap::Base *); @@ -74,6 +79,7 @@ struct VTable typedef bool (*SetPrototypeOf)(Managed *, const Object *); typedef qint64 (*GetLength)(const Managed *m); typedef void (*AdvanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); + typedef OwnPropertyKeyIterator *(*OwnPropertyKeys)(const Object *m); typedef ReturnedValue (*InstanceOf)(const Object *typeObject, const Value &var); typedef ReturnedValue (*Call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); @@ -109,6 +115,7 @@ struct VTable SetPrototypeOf setPrototypeOf; GetLength getLength; AdvanceIterator advanceIterator; + OwnPropertyKeys ownPropertyKeys; InstanceOf instanceOf; Call call; @@ -133,6 +140,7 @@ protected: static constexpr VTable::SetPrototypeOf virtualSetPrototypeOf = nullptr; static constexpr VTable::GetLength virtualGetLength = nullptr; static constexpr VTable::AdvanceIterator virtualAdvanceIterator = nullptr; + static constexpr VTable::OwnPropertyKeys virtualOwnPropertyKeys = nullptr; static constexpr VTable::InstanceOf virtualInstanceOf = nullptr; static constexpr VTable::Call virtualCall = nullptr; @@ -172,6 +180,7 @@ protected: classname::virtualSetPrototypeOf, \ classname::virtualGetLength, \ classname::virtualAdvanceIterator, \ + classname::virtualOwnPropertyKeys, \ classname::virtualInstanceOf, \ \ classname::virtualCall, \ |