aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4managed.cpp5
-rw-r--r--src/qml/jsruntime/qv4object.cpp72
-rw-r--r--src/qml/jsruntime/qv4object_p.h17
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp81
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h22
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp12
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h3
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp68
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h6
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp34
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp56
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h9
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, \