aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4objectiterator.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-02 15:44:12 +0200
committerLars Knoll <lars.knoll@qt.io>2018-08-02 20:25:41 +0000
commit0754f55287f4652382332bce42cd8c7d27846ef1 (patch)
tree490bbd3c5d66586a1427ba21dde76b2af65230dc /src/qml/jsruntime/qv4objectiterator.cpp
parent57640959320c87850315eae44c783803d113dc85 (diff)
Introduce a new mechanism to iterate over object properties
The old advanceIterator schema was extremely ugly and in addition not flexible enough to support the requirements for Proxy.ownKeys and some of the methods in Object Implemented a new scheme through a OwnPropertyKeys method in the Object VTable that creates and returns an iterator object. Ported QJSValueIterator and for-in to use the new mechanism. There's still many places where we use the old ObjectIterator (that relies on advanceIterator). Those will be ported in subsequent commits. Change-Id: I091a9bea9ff6b2b63630cc336814700757a718be Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4objectiterator.cpp')
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp81
1 files changed, 67 insertions, 14 deletions
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();
+}