From 430dfd326cb9d8dab8ebd11e83dd52e6d55c4229 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 30 Sep 2013 13:48:05 +0200 Subject: Fix ObjectIterator API to be GC safe Change-Id: I3a9c48d53d8dbadcb9b32c00fcef1f89447c4b8c Reviewed-by: Simon Hausmann --- src/imports/localstorage/plugin.cpp | 7 +-- src/qml/jsapi/qjsvalueiterator.cpp | 65 +++++++++++++++++----- src/qml/jsapi/qjsvalueiterator_p.h | 6 +- src/qml/jsruntime/qv4debugging.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 3 +- src/qml/jsruntime/qv4engine_p.h | 2 +- src/qml/jsruntime/qv4jsonobject.cpp | 14 ++--- src/qml/jsruntime/qv4managed.cpp | 5 ++ src/qml/jsruntime/qv4managed_p.h | 5 +- src/qml/jsruntime/qv4object.cpp | 17 +----- src/qml/jsruntime/qv4object_p.h | 18 +----- src/qml/jsruntime/qv4objectiterator.cpp | 98 +++++++++++++++++++++++++-------- src/qml/jsruntime/qv4objectiterator_p.h | 34 ++++++++++-- src/qml/jsruntime/qv4objectproto.cpp | 12 ++-- src/qml/jsruntime/qv4qobjectwrapper.cpp | 16 ++---- src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 +- src/qml/jsruntime/qv4regexp.cpp | 2 +- src/qml/jsruntime/qv4regexp_p.h | 2 +- src/qml/jsruntime/qv4runtime.cpp | 2 +- src/qml/jsruntime/qv4scopedvalue_p.h | 15 ++++- src/qml/jsruntime/qv4sequenceobject.cpp | 6 +- src/qml/jsruntime/qv4stringobject.cpp | 3 +- src/qml/jsruntime/qv4stringobject_p.h | 2 +- src/qml/jsruntime/qv4value_def_p.h | 2 + src/qml/qml/qqmllistwrapper.cpp | 4 +- src/qml/qml/qqmllistwrapper_p.h | 2 +- src/qml/qml/v8/qv8engine.cpp | 7 +-- src/qml/types/qqmldelegatemodel.cpp | 7 +-- src/qml/types/qqmllistmodel.cpp | 50 ++++++++--------- 29 files changed, 250 insertions(+), 160 deletions(-) (limited to 'src') diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 267b2b6395..ca69499478 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -276,14 +276,13 @@ static ReturnedValue qmlsqldatabase_executeSql(SimpleCallContext *ctx) query.bindValue(ii, engine->toVariant((v = array->getIndexed(ii)), -1)); } else if (values->asObject()) { ScopedObject object(scope, values); - ObjectIterator it(object.getPointer(), ObjectIterator::WithProtoChain|ObjectIterator::EnumerableOnly); + ObjectIterator it(scope, object, ObjectIterator::WithProtoChain|ObjectIterator::EnumerableOnly); ScopedValue key(scope); + QV4::ScopedValue val(scope); while (1) { - Value value; - key = it.nextPropertyName(&value); + key = it.nextPropertyName(val); if (key->isNull()) break; - QV4::ScopedValue val(scope, value); QVariant v = engine->toVariant(val, -1); if (key->isString()) { query.bindValue(key->stringValue()->toQString(), v); diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index b4156dcd1d..e1786f06cd 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -50,12 +50,20 @@ QT_BEGIN_NAMESPACE QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) : value(v) - , iterator(QJSValuePrivate::get(v)->value.asObject(), QV4::ObjectIterator::NoFlags) - , currentName(0) , currentIndex(UINT_MAX) - , nextName(0) , nextIndex(UINT_MAX) { + QJSValuePrivate *jsp = QJSValuePrivate::get(value); + QV4::ExecutionEngine *e = jsp->engine; + if (!e) + return; + + QV4::Scope scope(e); + QV4::ScopedObject o(scope, jsp->value); + iterator = e->newForEachIteratorObject(e->current, o)->asReturnedValue(); + + currentName = (QV4::String *)0; + nextName = (QV4::String *)0; } @@ -96,7 +104,13 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) QJSValueIterator::QJSValueIterator(const QJSValue& object) : d_ptr(new QJSValueIteratorPrivate(object)) { - d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); + QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); + if (!v4) + return; + QV4::Scope scope(v4); + QV4::Scoped it(scope, d_ptr->iterator.value()); + it->it.flags = QV4::ObjectIterator::NoFlags; + it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); } /*! @@ -117,7 +131,7 @@ bool QJSValueIterator::hasNext() const { if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) return false; - return d_ptr->nextName != 0 || d_ptr->nextIndex != UINT_MAX; + return !!d_ptr->nextName || d_ptr->nextIndex != UINT_MAX; } /*! @@ -139,8 +153,13 @@ bool QJSValueIterator::next() d_ptr->currentIndex = d_ptr->nextIndex; d_ptr->currentAttributes = d_ptr->nextAttributes; - d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); - return d_ptr->nextName != 0 || d_ptr->nextIndex != UINT_MAX; + QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); + if (!v4) + return false; + QV4::Scope scope(v4); + QV4::Scoped it(scope, d_ptr->iterator.value()); + it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); + return !!d_ptr->nextName || d_ptr->nextIndex != UINT_MAX; } /*! @@ -153,7 +172,7 @@ QString QJSValueIterator::name() const { if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) return QString(); - if (d_ptr->currentName) + if (!!d_ptr->currentName) return d_ptr->currentName->toQString(); if (d_ptr->currentIndex < UINT_MAX) return QString::number(d_ptr->currentIndex); @@ -172,14 +191,18 @@ QJSValue QJSValueIterator::value() const if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) return QJSValue(); - QV4::Object *o = d_ptr->iterator.object; - QV4::ExecutionEngine *engine = o->internalClass->engine; + QV4::ExecutionEngine *engine = d_ptr->iterator.engine(); + if (!engine) + return QJSValue(); + QV4::Scope scope(engine); + QV4::Scoped it(scope, d_ptr->iterator.value()); + QV4::ScopedObject o(scope, it->it.object); QV4::ExecutionContext *ctx = engine->current; try { QV4::ScopedValue v(scope); - if (d_ptr->currentName) { + if (!!d_ptr->currentName) { QV4::ScopedString n(scope, d_ptr->currentName); v = o->get(n); } else if (d_ptr->currentIndex != UINT_MAX) { @@ -202,8 +225,24 @@ QJSValue QJSValueIterator::value() const */ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) { - d_ptr->iterator = QV4::ObjectIterator(QJSValuePrivate::get(object)->value.asObject(), QV4::ObjectIterator::NoFlags); - d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); + d_ptr->value = object; + d_ptr->currentIndex = UINT_MAX; + d_ptr->nextIndex = UINT_MAX; + d_ptr->currentName = (QV4::String *)0; + d_ptr->nextName = (QV4::String *)0; + QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); + if (!v4) { + d_ptr->iterator = QV4::Encode::undefined(); + return *this; + } + + QJSValuePrivate *jsp = QJSValuePrivate::get(object); + QV4::Scope scope(v4); + QV4::ScopedObject o(scope, jsp->value); + d_ptr->iterator = v4->newForEachIteratorObject(v4->current, o)->asReturnedValue(); + QV4::Scoped it(scope, d_ptr->iterator.value()); + it->it.flags = QV4::ObjectIterator::NoFlags; + it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); return *this; } diff --git a/src/qml/jsapi/qjsvalueiterator_p.h b/src/qml/jsapi/qjsvalueiterator_p.h index 7687f896a1..b7a9b4a190 100644 --- a/src/qml/jsapi/qjsvalueiterator_p.h +++ b/src/qml/jsapi/qjsvalueiterator_p.h @@ -55,12 +55,12 @@ public: QJSValueIteratorPrivate(const QJSValue &v); QJSValue value; - QV4::ObjectIterator iterator; + QV4::PersistentValue iterator; QV4::PropertyAttributes currentAttributes; - QV4::String *currentName; + QV4::SafeString currentName; uint currentIndex; QV4::PropertyAttributes nextAttributes; - QV4::String *nextName; + QV4::SafeString nextName; uint nextIndex; }; diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index b4da4bba87..f95178c8f7 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -245,7 +245,7 @@ static void realDumpValue(QV4::Value v, QV4::ExecutionContext *ctx, std::string return; } - Object *o = v.objectValue(); + ScopedObject o(scope, v); if (!o) return; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 8808678b54..7b9071ed43 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -535,7 +536,7 @@ Returned *ExecutionEngine::newVariantObject(const QVariant &v) return o->asReturned(); } -Returned *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, Object *o) +Returned *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o) { Object *obj = new (memoryManager) ForEachIteratorObject(ctx, o); return obj->asReturned(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 32dcac4512..d93202df6e 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -301,7 +301,7 @@ struct Q_QML_EXPORT ExecutionEngine Returned *newVariantObject(const QVariant &v); - Returned *newForEachIteratorObject(ExecutionContext *ctx, Object *o); + Returned *newForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o); Returned *qmlContextObject() const; diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 3649163626..10d30756a1 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -791,16 +791,14 @@ QString Stringify::JO(ObjectRef o) QStringList partial; if (propertyList.isEmpty()) { - ObjectIterator it(o.getPointer(), ObjectIterator::EnumerableOnly); + ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); ScopedValue val(scope); while (1) { - Value v; - name = it.nextPropertyNameAsString(&v); + name = it.nextPropertyNameAsString(val); if (name->isNull()) break; - val = v; QString key = name->toQStringNoThrow(); QString member = makeMember(key, val); if (!member.isEmpty()) @@ -1024,16 +1022,14 @@ QJsonObject JsonObject::toJsonObject(ObjectRef o, V4ObjectSet &visitedObjects) visitedObjects.insert(o); - ObjectIterator it(o, ObjectIterator::EnumerableOnly); + ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); + QV4::ScopedValue val(scope); while (1) { - Value v; - name = it.nextPropertyNameAsString(&v); + name = it.nextPropertyNameAsString(val); if (name->isNull()) break; - QV4::ScopedValue val(scope, v); - QString key = name->toQStringNoThrow(); if (!val->asFunctionObject()) result.insert(key, toJsonValue(val, visitedObjects)); diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index f5715d51ec..03608d2556 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -241,3 +241,8 @@ bool Managed::deleteProperty(const StringRef name) { return vtbl->deleteProperty(this, name); } + +Property *Managed::advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes) +{ + return vtbl->advanceIterator(this, it, name, index, attributes); +} diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index c369353422..aca41bed06 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -108,7 +108,7 @@ struct ManagedVTable ReturnedValue (*getLookup)(Managed *m, Lookup *l); void (*setLookup)(Managed *m, Lookup *l, const ValueRef v); bool (*isEqualTo)(Managed *m, Managed *other); - Property *(*advanceIterator)(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); + Property *(*advanceIterator)(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); const char *className; }; @@ -278,8 +278,7 @@ public: bool isEqualTo(Managed *other) { return vtbl->isEqualTo(this, other); } - Property *advanceIterator(ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes) - { return vtbl->advanceIterator(this, it, name, index, attributes); } + Property *advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); static void destroy(Managed *that) { that->_data = 0; } static bool hasInstance(Managed *that, const ValueRef value); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index ed2bf09bb7..399cd2e0bd 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -544,10 +544,10 @@ void Object::setLookup(Managed *m, Lookup *l, const ValueRef value) l->setter = Lookup::setterInsert2; } -Property *Object::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) +Property *Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs) { Object *o = static_cast(m); - *name = 0; + name = (String *)0; *index = UINT_MAX; if (!it->arrayIndex) @@ -595,7 +595,7 @@ Property *Object::advanceIterator(Managed *m, ObjectIterator *it, String **name, PropertyAttributes a = o->internalClass->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { - *name = n; + name = n; if (attrs) *attrs = a; return p; @@ -1435,14 +1435,3 @@ QStringList ArrayObject::toQStringList() const } return result; } - - -DEFINE_MANAGED_VTABLE(ForEachIteratorObject); - -void ForEachIteratorObject::markObjects(Managed *that) -{ - ForEachIteratorObject *o = static_cast(that); - Object::markObjects(that); - if (o->it.object) - o->it.object->mark(); -} diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index c28edcae66..77f8d11e4f 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -49,7 +49,6 @@ #include "qv4managed_p.h" #include "qv4property_p.h" #include "qv4internalclass_p.h" -#include "qv4objectiterator_p.h" #include "qv4sparsearray_p.h" #include @@ -314,7 +313,7 @@ protected: static bool deleteIndexedProperty(Managed *m, uint index); static ReturnedValue getLookup(Managed *m, Lookup *l); static void setLookup(Managed *m, Lookup *l, const ValueRef v); - static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); + static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); private: @@ -329,21 +328,6 @@ private: friend struct ObjectPrototype; }; -struct ForEachIteratorObject: Object { - Q_MANAGED - ObjectIterator it; - ForEachIteratorObject(ExecutionContext *ctx, Object *o) - : Object(ctx->engine), it(o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { - vtbl = &static_vtbl; - type = Type_ForeachIteratorObject; - } - - ReturnedValue nextPropertyName() { return it.nextPropertyNameAsString(); } - -protected: - static void markObjects(Managed *that); -}; - struct BooleanObject: Object { SafeValue value; BooleanObject(ExecutionEngine *engine, const ValueRef val) diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index fc85a3f04c..2030489ea1 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -45,22 +45,40 @@ using namespace QV4; -ObjectIterator::ObjectIterator(Object *o, uint flags) - : object(o) - , current(o) +ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const ObjectRef o, uint flags) + : object(*scratch1) + , current(*scratch2) , arrayNode(0) , arrayIndex(0) , memberIndex(0) , flags(flags) { + object = o; + current = o; tmpDynamicProperty.value = Primitive::undefinedValue(); } -Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *attrs) +ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags) + : object(*static_cast(scope.alloc(1))) + , current(*static_cast(scope.alloc(1))) + , arrayNode(0) + , arrayIndex(0) + , memberIndex(0) + , flags(flags) { - Property *p = 0; - *name = 0; + object = o; + current = o; + tmpDynamicProperty.value = Primitive::undefinedValue(); +} + +Property *ObjectIterator::next(StringRef name, uint *index, PropertyAttributes *attrs) +{ + name = (String *)0; *index = UINT_MAX; + if (!object) + return 0; + + Property *p = 0; while (1) { if (!current) break; @@ -69,10 +87,8 @@ Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *a // check the property is not already defined earlier in the proto chain if (current != object) { Property *pp; - if (*name) { - Scope scope(object->engine()); - ScopedString n(scope, *name); - pp = object->__getPropertyDescriptor__(n); + if (name) { + pp = object->__getPropertyDescriptor__(name); } else { assert (*index != UINT_MAX); pp = object->__getPropertyDescriptor__(*index); @@ -86,7 +102,7 @@ Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *a if (flags & WithProtoChain) current = current->prototype(); else - current = 0; + current = (Object *)0; arrayIndex = 0; memberIndex = 0; @@ -94,38 +110,74 @@ Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *a return 0; } -ReturnedValue ObjectIterator::nextPropertyName(Value *value) +ReturnedValue ObjectIterator::nextPropertyName(ValueRef value) { + if (!object) + return Encode::null(); + PropertyAttributes attrs; uint index; - String *name; - Property *p = next(&name, &index, &attrs); + Scope scope(object->engine()); + ScopedString name(scope); + Property *p = next(name, &index, &attrs); if (!p) return Encode::null(); - if (value) - *value = Value::fromReturnedValue(object->getValue(p, attrs)); + value = Value::fromReturnedValue(object->getValue(p, attrs)); - if (name) + if (!!name) return name->asReturnedValue(); assert(index < UINT_MAX); return Encode(index); } -ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) +ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value) { + if (!object) + return Encode::null(); + PropertyAttributes attrs; uint index; - String *name; - Property *p = next(&name, &index, &attrs); + Scope scope(object->engine()); + ScopedString name(scope); + Property *p = next(name, &index, &attrs); if (!p) return Encode::null(); - if (value) - *value = Value::fromReturnedValue(object->getValue(p, attrs)); + value = Value::fromReturnedValue(object->getValue(p, attrs)); - if (name) + if (!!name) return name->asReturnedValue(); assert(index < UINT_MAX); return Encode(object->engine()->newString(QString::number(index))); } + +ReturnedValue ObjectIterator::nextPropertyNameAsString() +{ + if (!object) + return Encode::null(); + + PropertyAttributes attrs; + uint index; + Scope scope(object->engine()); + ScopedString name(scope); + Property *p = next(name, &index, &attrs); + if (!p) + return Encode::null(); + + if (!!name) + return name->asReturnedValue(); + assert(index < UINT_MAX); + return Encode(object->engine()->newString(QString::number(index))); +} + + +DEFINE_MANAGED_VTABLE(ForEachIteratorObject); + +void ForEachIteratorObject::markObjects(Managed *that) +{ + ForEachIteratorObject *o = static_cast(that); + o->workArea[0].mark(); + o->workArea[1].mark(); + Object::markObjects(that); +} diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index d5464891f1..e38fa8d7b6 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -43,6 +43,8 @@ #include "qv4global_p.h" #include "qv4property_p.h" +#include "qv4scopedvalue_p.h" +#include "qv4object_p.h" QT_BEGIN_NAMESPACE @@ -65,8 +67,8 @@ struct Q_QML_EXPORT ObjectIterator WithProtoChain = 0x2, }; - Object *object; - Object *current; + ObjectRef object; + ObjectRef current; SparseArrayNode *arrayNode; uint arrayIndex; uint memberIndex; @@ -74,12 +76,32 @@ struct Q_QML_EXPORT ObjectIterator Property tmpDynamicProperty; - ObjectIterator(Object *o, uint flags); - Property *next(String **name, uint *index, PropertyAttributes *attributes = 0); - ReturnedValue nextPropertyName(Value *value = 0); - ReturnedValue nextPropertyNameAsString(Value *value = 0); + ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const ObjectRef o, uint flags); + ObjectIterator(Scope &scope, const ObjectRef o, uint flags); + Property *next(StringRef name, uint *index, PropertyAttributes *attributes = 0); + ReturnedValue nextPropertyName(ValueRef value); + ReturnedValue nextPropertyNameAsString(ValueRef value); + ReturnedValue nextPropertyNameAsString(); }; +struct ForEachIteratorObject: Object { + Q_MANAGED + ObjectIterator it; + ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o) + : Object(ctx->engine), it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { + vtbl = &static_vtbl; + type = Type_ForeachIteratorObject; + } + + ReturnedValue nextPropertyName() { return it.nextPropertyNameAsString(); } + +protected: + static void markObjects(Managed *that); + + SafeObject workArea[2]; +}; + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 65fd2188ac..20a5c51692 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -222,14 +222,12 @@ ReturnedValue ObjectPrototype::method_defineProperties(SimpleCallContext *ctx) Scoped o(scope, ctx->argument(1), Scoped::Convert); ScopedValue val(scope); - ObjectIterator it(o.getPointer(), ObjectIterator::EnumerableOnly); + ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); + ScopedString name(scope); while (1) { uint index; - ScopedString name(scope); PropertyAttributes attrs; - String *tmp = 0; - Property *pd = it.next(&tmp, &index, &attrs); - name = tmp; + Property *pd = it.next(name, &index, &attrs); if (!pd) break; Property n; @@ -375,7 +373,7 @@ ReturnedValue ObjectPrototype::method_keys(SimpleCallContext *ctx) Scoped a(scope, ctx->engine->newArrayObject()); - ObjectIterator it(o.getPointer(), ObjectIterator::EnumerableOnly); + ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); while (1) { name = it.nextPropertyNameAsString(); @@ -652,7 +650,7 @@ Returned *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, Scoped array(scope, v4->newArrayObject()); ScopedObject O(scope, o); if (O) { - ObjectIterator it(O.getPointer(), ObjectIterator::NoFlags); + ObjectIterator it(scope, O, ObjectIterator::NoFlags); ScopedValue name(scope); while (1) { name = it.nextPropertyNameAsString(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 53e915c1a4..90a1950395 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -646,13 +646,11 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name) return QV4::Object::query(m, name); } -Property *QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes) +Property *QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes) { - *name = 0; + name = (String *)0; *index = UINT_MAX; - QV4::Scope scope(m->engine()); - QObjectWrapper *that = static_cast(m); if (!that->m_object) @@ -661,22 +659,20 @@ Property *QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String const QMetaObject *mo = that->m_object->metaObject(); const int propertyCount = mo->propertyCount(); if (it->arrayIndex < propertyCount) { - ScopedString n(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); - *name = n.getPointer(); + name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name())); ++it->arrayIndex; if (attributes) *attributes = QV4::Attr_Data; - it->tmpDynamicProperty.value = that->get(n); + it->tmpDynamicProperty.value = that->get(name); return &it->tmpDynamicProperty; } const int methodCount = mo->methodCount(); if (it->arrayIndex < propertyCount + methodCount) { - ScopedString n(scope, that->engine()->newString(QString::fromUtf8(mo->method(it->arrayIndex - propertyCount).name()))); - *name = n.getPointer(); + name = that->engine()->newString(QString::fromUtf8(mo->method(it->arrayIndex - propertyCount).name())); ++it->arrayIndex; if (attributes) *attributes = QV4::Attr_Data; - it->tmpDynamicProperty.value = that->get(n); + it->tmpDynamicProperty.value = that->get(name); return &it->tmpDynamicProperty; } return QV4::Object::advanceIterator(m, it, name, index, attributes); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 74c436ca64..7b9e985f21 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -108,7 +108,7 @@ private: static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); static void put(Managed *m, const StringRef name, const ValueRef value); static PropertyAttributes query(const Managed *, StringRef name); - static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); + static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); static void markObjects(Managed *that); static void collectDeletables(Managed *m, GCDeletable **deletable); static void destroy(Managed *that) diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index bc0955f547..103605ee7a 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -174,7 +174,7 @@ bool RegExp::deleteIndexedProperty(Managed *m, uint index) return false; } -Property *RegExp::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes) +Property *RegExp::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes) { return 0; } diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 8aa173ca38..f674bea042 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -119,7 +119,7 @@ protected: static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *, const StringRef); static bool deleteIndexedProperty(Managed *m, uint index); - static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); + static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); private: friend class RegExpCache; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 8187da6556..1dd35fcee2 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -544,7 +544,7 @@ ReturnedValue __qmljs_foreach_iterator_object(ExecutionContext *ctx, const Value Scoped o(scope, (Object *)0); if (!in->isNullOrUndefined()) o = in; - Scoped it(scope, ctx->engine->newForEachIteratorObject(ctx, o.getPointer())); + Scoped it(scope, ctx->engine->newForEachIteratorObject(ctx, o)); return it.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 3a7526197e..a1f6f4b2ac 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -463,9 +463,18 @@ struct Referenced { Referenced &operator=(const Referenced &o) { *ptr = *o.ptr; return *this; } Referenced &operator=(T *t) - { ptr->val = t->asReturnedValue(); return *this; } - Referenced &operator=(const Returned *t) { - ptr->val = t->getPointer()->asReturnedValue(); + { +#if QT_POINTER_SIZE == 4 + ptr->tag = Value::Managed_Type; +#endif + ptr->m = t; + return *this; + } + Referenced &operator=(Returned *t) { +#if QT_POINTER_SIZE == 4 + ptr->tag = Value::Managed_Type; +#endif + ptr->m = t->getPointer(); return *this; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 6b55a09486..10293a7d9e 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -277,9 +277,9 @@ public: return (signedIdx < m_container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; } - Property *containerAdvanceIterator(ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) + Property *containerAdvanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs) { - *name = 0; + name = (String *)0; *index = UINT_MAX; if (m_isReference) { @@ -500,7 +500,7 @@ private: { return static_cast *>(that)->containerDeleteIndexedProperty(index); } static bool isEqualTo(Managed *that, Managed *other) { return static_cast *>(that)->containerIsEqualTo(other); } - static Property *advanceIterator(Managed *that, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) + static Property *advanceIterator(Managed *that, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs) { return static_cast *>(that)->containerAdvanceIterator(it, name, index, attrs); } static void destroy(Managed *that) diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index fd15d7ef73..7e503e4b1a 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -127,8 +127,9 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) return true; } -Property *StringObject::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) +Property *StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs) { + name = (String *)0; StringObject *s = static_cast(m); uint slen = s->value.stringValue()->toQString().length(); if (it->arrayIndex < slen) { diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index e02a6a759f..08892d1222 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -62,7 +62,7 @@ struct StringObject: Object { protected: StringObject(InternalClass *ic); - static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs); + static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs); static void markObjects(Managed *that); }; diff --git a/src/qml/jsruntime/qv4value_def_p.h b/src/qml/jsruntime/qv4value_def_p.h index 4ee277ca38..76f41dca71 100644 --- a/src/qml/jsruntime/qv4value_def_p.h +++ b/src/qml/jsruntime/qv4value_def_p.h @@ -386,6 +386,8 @@ struct Safe : public SafeValue Safe &operator =(const Safe &t); + bool operator!() const { return !managed(); } + // ### GC: remove me operator T*() { return static_cast(managed()); } Value *operator->() { return this; } diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 523b7cc5de..de4fbbb408 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -147,9 +147,9 @@ void QmlListWrapper::destroy(Managed *that) w->~QmlListWrapper(); } -Property *QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs) +Property *QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attrs) { - *name = 0; + name = (String *)0; *index = UINT_MAX; QmlListWrapper *w = m->as(); quint32 count = w->property.count ? w->property.count(&w->property) : 0; diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index ea35ad091d..9ece5851ed 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -84,7 +84,7 @@ public: static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); static void put(Managed *m, const StringRef name, const ValueRef value); - static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes); + static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes); static void destroy(Managed *that); private: diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 9211ffd484..7cf769a219 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -613,16 +613,15 @@ QVariantMap QV8Engine::variantMapFromJS(QV4::ObjectRef o, visitedObjects.insert(o); - QV4::ObjectIterator it(o, QV4::ObjectIterator::EnumerableOnly); + QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly); QV4::ScopedValue name(scope); + QV4::ScopedValue val(scope); while (1) { - QV4::Value v; - name = it.nextPropertyNameAsString(&v); + name = it.nextPropertyNameAsString(val); if (name->isNull()) break; QString key = name->toQStringNoThrow(); - QV4::ScopedValue val(scope, v); result.insert(key, variantFromJS(val, visitedObjects)); } diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index f929880f58..b87ed63f2b 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1557,14 +1557,13 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const if (!o) return false; - QV4::ObjectIterator it(o.getPointer(), QV4::ObjectIterator::EnumerableOnly|QV4::ObjectIterator::WithProtoChain); + QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly|QV4::ObjectIterator::WithProtoChain); QV4::ScopedValue propertyName(scope); + QV4::ScopedValue v(scope); while (1) { - QV4::Value value; - propertyName = it.nextPropertyNameAsString(&value); + propertyName = it.nextPropertyNameAsString(v); if (propertyName->isNull()) break; - QV4::ScopedValue v(scope, value); cacheItem->setValue(propertyName->toQStringNoThrow(), m_cacheMetaType->v8Engine->toVariant(v, QVariant::Invalid)); } diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index f5e0e70035..0ff348790c 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -415,13 +415,13 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector *roles QV4::ExecutionEngine *v4 = object->engine(); QV4::Scope scope(v4); - QV4::Scoped o(scope); + QV4::ScopedObject o(scope); - QV4::ObjectIterator it(object, QV4::ObjectIterator::WithProtoChain|QV4::ObjectIterator::EnumerableOnly); + QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::WithProtoChain|QV4::ObjectIterator::EnumerableOnly); QV4::Scoped propertyName(scope); + QV4::ScopedValue propertyValue(scope); while (1) { - QV4::Value propertyValue; - propertyName = it.nextPropertyNameAsString(&propertyValue); + propertyName = it.nextPropertyNameAsString(propertyValue); if (!propertyName) break; @@ -429,13 +429,13 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector *roles int roleIndex = -1; // Add the value now - if (QV4::String *s = propertyValue.asString()) { + if (QV4::String *s = propertyValue->asString()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::String); roleIndex = e->setStringProperty(r, s->toQString()); - } else if (propertyValue.isNumber()) { + } else if (propertyValue->isNumber()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Number); - roleIndex = e->setDoubleProperty(r, propertyValue.asDouble()); - } else if (QV4::ArrayObject *a = propertyValue.asArrayObject()) { + roleIndex = e->setDoubleProperty(r, propertyValue->asDouble()); + } else if (QV4::ArrayObject *a = propertyValue->asArrayObject()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::List); ListModel *subModel = new ListModel(r.subLayout, 0, -1); @@ -446,14 +446,14 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector *roles } roleIndex = e->setListProperty(r, subModel); - } else if (propertyValue.isBoolean()) { + } else if (propertyValue->isBoolean()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Bool); - roleIndex = e->setBoolProperty(r, propertyValue.booleanValue()); - } else if (QV4::DateObject *dd = propertyValue.asDateObject()) { + roleIndex = e->setBoolProperty(r, propertyValue->booleanValue()); + } else if (QV4::DateObject *dd = propertyValue->asDateObject()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::DateTime); QDateTime dt = dd->toQDateTime(); roleIndex = e->setDateTimeProperty(r, dt); - } else if (QV4::Object *o = propertyValue.asObject()) { + } else if (QV4::Object *o = propertyValue->asObject()) { if (QV4::QObjectWrapper *wrapper = o->as()) { QObject *o = wrapper->object(); const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::QObject); @@ -466,7 +466,7 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector *roles roleIndex = e->setVariantMapProperty(role, obj, eng); } } - } else if (propertyValue.isNullOrUndefined()) { + } else if (propertyValue->isNullOrUndefined()) { const ListLayout::Role *r = m_layout->getExistingRole(propertyName.getPointer()); if (r) e->clearProperty(*r); @@ -489,25 +489,25 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng) QV4::Scope scope(v4); QV4::Scoped o(scope); - QV4::ObjectIterator it(object, QV4::ObjectIterator::WithProtoChain|QV4::ObjectIterator::EnumerableOnly); + QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::WithProtoChain|QV4::ObjectIterator::EnumerableOnly); QV4::Scoped propertyName(scope); + QV4::ScopedValue propertyValue(scope); while (1) { - QV4::Value propertyValue; - propertyName = it.nextPropertyNameAsString(&propertyValue); + propertyName = it.nextPropertyNameAsString(propertyValue); if (!propertyName) break; // Add the value now - if (QV4::String *s = propertyValue.asString()) { + if (QV4::String *s = propertyValue->asString()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::String); if (r.type == ListLayout::Role::String) e->setStringPropertyFast(r, s->toQString()); - } else if (propertyValue.isNumber()) { + } else if (propertyValue->isNumber()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Number); if (r.type == ListLayout::Role::Number) { - e->setDoublePropertyFast(r, propertyValue.asDouble()); + e->setDoublePropertyFast(r, propertyValue->asDouble()); } - } else if (QV4::ArrayObject *a = propertyValue.asArrayObject()) { + } else if (QV4::ArrayObject *a = propertyValue->asArrayObject()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::List); if (r.type == ListLayout::Role::List) { ListModel *subModel = new ListModel(r.subLayout, 0, -1); @@ -520,18 +520,18 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng) e->setListPropertyFast(r, subModel); } - } else if (propertyValue.isBoolean()) { + } else if (propertyValue->isBoolean()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Bool); if (r.type == ListLayout::Role::Bool) { - e->setBoolPropertyFast(r, propertyValue.booleanValue()); + e->setBoolPropertyFast(r, propertyValue->booleanValue()); } - } else if (QV4::DateObject *dd = propertyValue.asDateObject()) { + } else if (QV4::DateObject *dd = propertyValue->asDateObject()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::DateTime); if (r.type == ListLayout::Role::DateTime) { QDateTime dt = dd->toQDateTime();; e->setDateTimePropertyFast(r, dt); } - } else if (propertyValue.isObject()) { + } else if (propertyValue->isObject()) { QV4::ScopedObject o(scope, propertyValue); if (QV4::QObjectWrapper *wrapper = o->as()) { QObject *o = wrapper->object(); @@ -543,7 +543,7 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng) if (role.type == ListLayout::Role::VariantMap) e->setVariantMapFast(role, o, eng); } - } else if (propertyValue.isUndefined() || propertyValue.isNull()) { + } else if (propertyValue->isNullOrUndefined()) { const ListLayout::Role *r = m_layout->getExistingRole(propertyName.getPointer()); if (r) e->clearProperty(*r); -- cgit v1.2.3