diff options
author | Lars Knoll <lars.knoll@theqtcompany.com> | 2015-01-12 21:55:51 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2015-01-16 21:12:49 +0100 |
commit | 8ffb79bbd214c239e414dc4e9cf4569b3219bdab (patch) | |
tree | c9cc7e596be2616f8c1211f4fb7623c9153cd7d6 /src/qml/jsapi | |
parent | 9fe1588915b935298917a0c29593eeed70da682f (diff) |
Refactor persistent values
Use a page wise allocation mechanism for persistent
values. This significantly reduces memory consumption
of persistent values and also improves their performance
a lot.
Change-Id: I8499d2ca5bdd871e029f643ae605a94544558bb5
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/jsapi')
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 105 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.cpp | 341 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue_p.h | 52 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalueiterator.cpp | 19 |
4 files changed, 324 insertions, 193 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 831287d0b3..d54af28f26 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -421,11 +421,18 @@ QJSValue QJSEngine::create(int type, const void *ptr) bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) { QJSValuePrivate *vp = QJSValuePrivate::get(value); - if (vp->engine) { - QV4::Scope scope(vp->engine); - QV4::ScopedValue v(scope, vp->getValue(scope.engine)); + QV4::ExecutionEngine *v4 = vp->engine(); + QV4::Value scratch; + QV4::Value *val = vp->valueForData(&scratch); + if (v4) { + QV4::Scope scope(v4); + QV4::ScopedValue v(scope, *val); return scope.engine->metaTypeFromJS(v, type, ptr); - } else if (vp->value.isEmpty()) { + } + + Q_ASSERT(vp->persistent.isEmpty()); + + if (!val) { if (vp->unboundData.userType() == QMetaType::QString) { QString string = vp->unboundData.toString(); // have a string based value without engine. Do conversion manually @@ -478,50 +485,52 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) } else { return QMetaType::convert(&vp->unboundData.data_ptr(), vp->unboundData.userType(), ptr, type); } - } else { - switch (type) { - case QMetaType::Bool: - *reinterpret_cast<bool*>(ptr) = vp->value.toBoolean(); - return true; - case QMetaType::Int: - *reinterpret_cast<int*>(ptr) = vp->value.toInt32(); - return true; - case QMetaType::UInt: - *reinterpret_cast<uint*>(ptr) = vp->value.toUInt32(); - return true; - case QMetaType::LongLong: - *reinterpret_cast<qlonglong*>(ptr) = vp->value.toInteger(); - return true; - case QMetaType::ULongLong: - *reinterpret_cast<qulonglong*>(ptr) = vp->value.toInteger(); - return true; - case QMetaType::Double: - *reinterpret_cast<double*>(ptr) = vp->value.toNumber(); - return true; - case QMetaType::QString: - *reinterpret_cast<QString*>(ptr) = value.toString(); - return true; - case QMetaType::Float: - *reinterpret_cast<float*>(ptr) = vp->value.toNumber(); - return true; - case QMetaType::Short: - *reinterpret_cast<short*>(ptr) = vp->value.toInt32(); - return true; - case QMetaType::UShort: - *reinterpret_cast<unsigned short*>(ptr) = vp->value.toUInt16(); - return true; - case QMetaType::Char: - *reinterpret_cast<char*>(ptr) = vp->value.toInt32(); - return true; - case QMetaType::UChar: - *reinterpret_cast<unsigned char*>(ptr) = vp->value.toUInt16(); - return true; - case QMetaType::QChar: - *reinterpret_cast<QChar*>(ptr) = vp->value.toUInt16(); - return true; - default: - return false; - } + } + + Q_ASSERT(val); + + switch (type) { + case QMetaType::Bool: + *reinterpret_cast<bool*>(ptr) = val->toBoolean(); + return true; + case QMetaType::Int: + *reinterpret_cast<int*>(ptr) = val->toInt32(); + return true; + case QMetaType::UInt: + *reinterpret_cast<uint*>(ptr) = val->toUInt32(); + return true; + case QMetaType::LongLong: + *reinterpret_cast<qlonglong*>(ptr) = val->toInteger(); + return true; + case QMetaType::ULongLong: + *reinterpret_cast<qulonglong*>(ptr) = val->toInteger(); + return true; + case QMetaType::Double: + *reinterpret_cast<double*>(ptr) = val->toNumber(); + return true; + case QMetaType::QString: + *reinterpret_cast<QString*>(ptr) = val->toQStringNoThrow(); + return true; + case QMetaType::Float: + *reinterpret_cast<float*>(ptr) = val->toNumber(); + return true; + case QMetaType::Short: + *reinterpret_cast<short*>(ptr) = val->toInt32(); + return true; + case QMetaType::UShort: + *reinterpret_cast<unsigned short*>(ptr) = val->toUInt16(); + return true; + case QMetaType::Char: + *reinterpret_cast<char*>(ptr) = val->toInt32(); + return true; + case QMetaType::UChar: + *reinterpret_cast<unsigned char*>(ptr) = val->toUInt16(); + return true; + case QMetaType::QChar: + *reinterpret_cast<QChar*>(ptr) = val->toUInt16(); + return true; + default: + return false; } } diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index d888ea3535..a158d3ad72 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -50,24 +50,50 @@ QV4::ReturnedValue QJSValuePrivate::getValue(QV4::ExecutionEngine *e) { - if (!this->engine) { - this->engine = e; - } else if (this->engine != e) { + QV4::ExecutionEngine *engine = persistent.engine(); + if (!engine) { + persistent = QV4::PersistentValue(e, e->fromVariant(unboundData)); + unboundData.clear(); + engine = e; + } + + if (engine != e) { qWarning("JSValue can't be reassigned to another engine."); return QV4::Encode::undefined(); } - if (value.isEmpty()) { - value = QV4::Encode(e->fromVariant(unboundData)); - PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues; - prev = listRoot; - next = *listRoot; - *prev = this; - if (next) - next->prev = &this->next; - unboundData.clear(); + return persistent.value(); +} + +QV4::Value QJSValuePrivate::primitiveValueForUnboundData() const +{ + QV4::Value v = QV4::Primitive::emptyValue(); + switch ((int)unboundData.type()) { + case QMetaType::UnknownType: + case QMetaType::Void: + v = QV4::Encode::undefined(); + break; + case QMetaType::VoidStar: + v = QV4::Encode::null(); + break; + case QMetaType::Bool: + v = QV4::Encode(unboundData.toBool()); + break; + case QMetaType::Double: + v = QV4::Encode(unboundData.toDouble()); + break; + case QMetaType::Int: + case QMetaType::Short: + case QMetaType::UShort: + case QMetaType::Char: + case QMetaType::UChar: + v = QV4::Encode(unboundData.toInt()); + break; + case QMetaType::UInt: + v = QV4::Encode(unboundData.toUInt()); + break; } - return value.asReturnedValue(); + return v; } /*! @@ -142,7 +168,7 @@ using namespace QV4; Constructs a new QJSValue with a boolean \a value. */ QJSValue::QJSValue(bool value) - : d(new QJSValuePrivate(Encode(value))) + : d(new QJSValuePrivate(QVariant(value))) { } @@ -155,7 +181,7 @@ QJSValue::QJSValue(QJSValuePrivate *dd) Constructs a new QJSValue with a number \a value. */ QJSValue::QJSValue(int value) - : d(new QJSValuePrivate(Encode(value))) + : d(new QJSValuePrivate(QVariant((double)value))) { } @@ -163,7 +189,7 @@ QJSValue::QJSValue(int value) Constructs a new QJSValue with a number \a value. */ QJSValue::QJSValue(uint value) - : d(new QJSValuePrivate(Encode(value))) + : d(new QJSValuePrivate(QVariant((double)value))) { } @@ -171,7 +197,7 @@ QJSValue::QJSValue(uint value) Constructs a new QJSValue with a number \a value. */ QJSValue::QJSValue(double value) - : d(new QJSValuePrivate(Encode(value))) + : d(new QJSValuePrivate(QVariant(value))) { } @@ -187,8 +213,10 @@ QJSValue::QJSValue(const QString& value) Constructs a new QJSValue with a special \a value. */ QJSValue::QJSValue(SpecialValue value) - : d(new QJSValuePrivate(value == UndefinedValue ? Encode::undefined() : Encode::null())) + : d(new QJSValuePrivate) { + if (value == NullValue) + d->unboundData = QVariant(QMetaType::VoidStar, (void *)0); } /*! @@ -238,7 +266,9 @@ QJSValue::~QJSValue() */ bool QJSValue::isBool() const { - return d->value.isBoolean(); + if (d->persistent.valueRef()) + return d->persistent.valueRef()->isBoolean(); + return d->unboundData.type() == QVariant::Bool; } /*! @@ -249,7 +279,9 @@ bool QJSValue::isBool() const */ bool QJSValue::isNumber() const { - return d->value.isNumber(); + if (d->persistent.valueRef()) + return d->persistent.valueRef()->isNumber(); + return d->unboundData.type() == QVariant::Double; } /*! @@ -258,7 +290,9 @@ bool QJSValue::isNumber() const */ bool QJSValue::isNull() const { - return d->value.isNull(); + if (d->persistent.valueRef()) + return d->persistent.valueRef()->isNull(); + return (int)d->unboundData.type() == QMetaType::VoidStar; } /*! @@ -269,7 +303,9 @@ bool QJSValue::isNull() const */ bool QJSValue::isString() const { - return d->value.isEmpty() || d->value.isString(); + if (d->persistent.valueRef()) + return d->persistent.valueRef()->isString(); + return (int)d->unboundData.type() == QMetaType::QString; } /*! @@ -278,7 +314,9 @@ bool QJSValue::isString() const */ bool QJSValue::isUndefined() const { - return d->value.isUndefined(); + if (d->persistent.valueRef()) + return d->persistent.valueRef()->isUndefined(); + return (int)d->unboundData.type() == QMetaType::UnknownType || (int)d->unboundData.type() == QMetaType::Void; } /*! @@ -287,7 +325,9 @@ bool QJSValue::isUndefined() const */ bool QJSValue::isError() const { - Object *o = d->value.asObject(); + if (d->persistent.isEmpty()) + return false; + Object *o = d->persistent.valueRef()->asObject(); return o && o->asErrorObject(); } @@ -299,7 +339,9 @@ bool QJSValue::isError() const */ bool QJSValue::isArray() const { - return d->value.asArrayObject(); + if (d->persistent.isEmpty()) + return false; + return d->persistent.valueRef()->asArrayObject(); } /*! @@ -313,7 +355,9 @@ bool QJSValue::isArray() const */ bool QJSValue::isObject() const { - return d->value.asObject(); + if (d->persistent.isEmpty()) + return false; + return d->persistent.valueRef()->asObject(); } /*! @@ -324,7 +368,9 @@ bool QJSValue::isObject() const */ bool QJSValue::isCallable() const { - return d->value.asFunctionObject(); + if (d->persistent.isEmpty()) + return false; + return d->persistent.valueRef()->asFunctionObject(); } /*! @@ -335,8 +381,9 @@ bool QJSValue::isCallable() const */ bool QJSValue::isVariant() const { - Managed *m = d->value.asManaged(); - return m ? m->as<QV4::VariantObject>() : 0; + if (d->persistent.isEmpty()) + return false; + return d->persistent.valueRef()->as<QV4::VariantObject>(); } /*! @@ -353,7 +400,10 @@ bool QJSValue::isVariant() const */ QString QJSValue::toString() const { - if (d->value.isEmpty()) { + QV4::Value scratch; + QV4::Value *val = d->valueForData(&scratch); + + if (!val) { if (d->unboundData.type() == QVariant::Map) return QStringLiteral("[object Object]"); else if (d->unboundData.type() == QVariant::List) { @@ -368,7 +418,7 @@ QString QJSValue::toString() const } return d->unboundData.toString(); } - return d->value.toQStringNoThrow(); + return val->toQStringNoThrow(); } /*! @@ -385,7 +435,10 @@ QString QJSValue::toString() const */ double QJSValue::toNumber() const { - if (d->value.isEmpty()) { + QV4::Value scratch; + QV4::Value *val = d->valueForData(&scratch); + + if (!val) { if (d->unboundData.type() == QVariant::String) return RuntimeHelpers::stringToNumber(d->unboundData.toString()); else if (d->unboundData.canConvert<double>()) @@ -394,9 +447,10 @@ double QJSValue::toNumber() const return std::numeric_limits<double>::quiet_NaN(); } - double dbl = d->value.toNumber(); - if (d->engine && d->engine->hasException) { - d->engine->catchException(); + double dbl = val->toNumber(); + QV4::ExecutionEngine *engine = d->persistent.engine(); + if (engine && engine->hasException) { + engine->catchException(); return 0; } return dbl; @@ -416,16 +470,20 @@ double QJSValue::toNumber() const */ bool QJSValue::toBool() const { - if (d->value.isEmpty()) { + QV4::Value scratch; + QV4::Value *val = d->valueForData(&scratch); + + if (!val) { if (d->unboundData.userType() == QMetaType::QString) return d->unboundData.toString().length() > 0; else return d->unboundData.toBool(); } - bool b = d->value.toBoolean(); - if (d->engine && d->engine->hasException) { - d->engine->catchException(); + bool b = val->toBoolean(); + QV4::ExecutionEngine *engine = d->persistent.engine(); + if (engine && engine->hasException) { + engine->catchException(); return false; } return b; @@ -445,16 +503,20 @@ bool QJSValue::toBool() const */ qint32 QJSValue::toInt() const { - if (d->value.isEmpty()) { + QV4::Value scratch; + QV4::Value *val = d->valueForData(&scratch); + + if (!val) { if (d->unboundData.userType() == QMetaType::QString) return QV4::Primitive::toInt32(RuntimeHelpers::stringToNumber(d->unboundData.toString())); else return d->unboundData.toInt(); } - qint32 i = d->value.toInt32(); - if (d->engine && d->engine->hasException) { - d->engine->catchException(); + qint32 i = val->toInt32(); + QV4::ExecutionEngine *engine = d->persistent.engine(); + if (engine && engine->hasException) { + engine->catchException(); return 0; } return i; @@ -474,16 +536,20 @@ qint32 QJSValue::toInt() const */ quint32 QJSValue::toUInt() const { - if (d->value.isEmpty()) { + QV4::Value scratch; + QV4::Value *val = d->valueForData(&scratch); + + if (!val) { if (d->unboundData.userType() == QMetaType::QString) return QV4::Primitive::toUInt32(RuntimeHelpers::stringToNumber(d->unboundData.toString())); else return d->unboundData.toUInt(); } - quint32 u = d->value.toUInt32(); - if (d->engine && d->engine->hasException) { - d->engine->catchException(); + quint32 u = val->toUInt32(); + QV4::ExecutionEngine *engine = d->persistent.engine(); + if (engine && engine->hasException) { + engine->catchException(); return 0; } return u; @@ -513,24 +579,24 @@ quint32 QJSValue::toUInt() const */ QVariant QJSValue::toVariant() const { - if (d->value.isEmpty()) + if (d->persistent.isEmpty()) return d->unboundData; - if (Object *o = d->value.asObject()) - return o->engine()->toVariant(d->value, /*typeHint*/ -1, /*createJSValueForObjects*/ false); - - if (d->value.isString()) - return QVariant(d->value.stringValue()->toQString()); - if (d->value.isBoolean()) - return QVariant(d->value.booleanValue()); - if (d->value.isNumber()) { - if (d->value.isInt32()) - return QVariant(d->value.integerValue()); - return QVariant(d->value.asDouble()); + if (Object *o = d->persistent.valueRef()->asObject()) + return o->engine()->toVariant(*d->persistent.valueRef(), /*typeHint*/ -1, /*createJSValueForObjects*/ false); + + if (d->persistent.valueRef()->isString()) + return QVariant(d->persistent.valueRef()->stringValue()->toQString()); + if (d->persistent.valueRef()->isBoolean()) + return QVariant(d->persistent.valueRef()->booleanValue()); + if (d->persistent.valueRef()->isNumber()) { + if (d->persistent.valueRef()->isInt32()) + return QVariant(d->persistent.valueRef()->integerValue()); + return QVariant(d->persistent.valueRef()->asDouble()); } - if (d->value.isNull()) + if (d->persistent.valueRef()->isNull()) return QVariant(QMetaType::VoidStar, 0); - Q_ASSERT(d->value.isUndefined()); + Q_ASSERT(d->persistent.valueRef()->isUndefined()); return QVariant(); } @@ -551,11 +617,14 @@ QVariant QJSValue::toVariant() const */ QJSValue QJSValue::call(const QJSValueList &args) { - FunctionObject *f = d->value.asFunctionObject(); + if (d->persistent.isEmpty()) + return QJSValue(); + + FunctionObject *f = d->persistent.valueRef()->asFunctionObject(); if (!f) return QJSValue(); - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->persistent.engine(); Q_ASSERT(engine); Scope scope(engine); @@ -570,8 +639,8 @@ QJSValue QJSValue::call(const QJSValueList &args) } ScopedValue result(scope, f->call(callData)); - if (d->engine->hasException) - result = d->engine->catchException(); + if (engine->hasException) + result = engine->catchException(); return new QJSValuePrivate(engine, result); } @@ -598,11 +667,14 @@ QJSValue QJSValue::call(const QJSValueList &args) */ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) { - FunctionObject *f = d->value.asFunctionObject(); + if (d->persistent.isEmpty()) + return QJSValue(); + + FunctionObject *f = d->persistent.valueRef()->asFunctionObject(); if (!f) return QJSValue(); - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->persistent.engine(); Q_ASSERT(engine); Scope scope(engine); @@ -622,8 +694,8 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList } ScopedValue result(scope, f->call(callData)); - if (d->engine->hasException) - result = d->engine->catchException(); + if (engine->hasException) + result = engine->catchException(); return new QJSValuePrivate(engine, result); } @@ -648,11 +720,14 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList */ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) { - FunctionObject *f = d->value.asFunctionObject(); + if (d->persistent.isEmpty()) + return QJSValue(); + + FunctionObject *f = d->persistent.valueRef()->asFunctionObject(); if (!f) return QJSValue(); - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->persistent.engine(); Q_ASSERT(engine); Scope scope(engine); @@ -666,8 +741,8 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) } ScopedValue result(scope, f->construct(callData)); - if (d->engine->hasException) - result = d->engine->catchException(); + if (engine->hasException) + result = engine->catchException(); return new QJSValuePrivate(engine, result); } @@ -683,7 +758,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) */ QJSEngine* QJSValue::engine() const { - QV4::ExecutionEngine *engine = d->engine; + QV4::ExecutionEngine *engine = d->persistent.engine(); if (engine) return engine->jsEngine(); return 0; @@ -700,11 +775,11 @@ QJSEngine* QJSValue::engine() const */ QJSValue QJSValue::prototype() const { - QV4::ExecutionEngine *engine = d->engine; + QV4::ExecutionEngine *engine = d->persistent.engine(); if (!engine) return QJSValue(); QV4::Scope scope(engine); - ScopedObject o(scope, d->value.asObject()); + ScopedObject o(scope, d->persistent.valueRef()->asObject()); if (!o) return QJSValue(); ScopedObject p(scope, o->prototype()); @@ -727,19 +802,20 @@ QJSValue QJSValue::prototype() const */ void QJSValue::setPrototype(const QJSValue& prototype) { - ExecutionEngine *v4 = d->engine; + ExecutionEngine *v4 = d->persistent.engine(); if (!v4) return; Scope scope(v4); - ScopedObject o(scope, d->value); + ScopedObject o(scope, d->persistent.value()); if (!o) return; - if (prototype.d->value.isNull()) { + prototype.d->getValue(v4); + if (prototype.d->persistent.valueRef()->isNull()) { o->setPrototype(0); return; } - ScopedObject p(scope, prototype.d->value); + ScopedObject p(scope, prototype.d->persistent.value()); if (!p) return; if (o->engine() != p->engine()) { @@ -809,17 +885,21 @@ static bool js_equal(const QString &string, QV4::ValueRef value) */ bool QJSValue::equals(const QJSValue& other) const { - if (d->value.isEmpty()) { - if (other.d->value.isEmpty()) + QV4::Value s1, s2; + QV4::Value *v = d->valueForData(&s1); + QV4::Value *ov = other.d->valueForData(&s2); + + if (!v) { + if (!ov) return d->unboundData == other.d->unboundData; if (d->unboundData.type() == QVariant::Map || d->unboundData.type() == QVariant::List) return false; - return js_equal(d->unboundData.toString(), QV4::ValueRef(other.d->value)); - } - if (other.d->value.isEmpty()) + return js_equal(d->unboundData.toString(), *ov); + } + if (!ov) return other.equals(*this); - return Runtime::compareEqual(QV4::ValueRef(d), QV4::ValueRef(other.d)); + return Runtime::compareEqual(*v, *ov); } /*! @@ -846,19 +926,23 @@ bool QJSValue::equals(const QJSValue& other) const */ bool QJSValue::strictlyEquals(const QJSValue& other) const { - if (d->value.isEmpty()) { - if (other.d->value.isEmpty()) + QV4::Value s1, s2; + QV4::Value *v = d->valueForData(&s1); + QV4::Value *ov = other.d->valueForData(&s2); + + if (!v) { + if (!ov) return d->unboundData == other.d->unboundData; if (d->unboundData.type() == QVariant::Map || d->unboundData.type() == QVariant::List) return false; - if (other.d->value.isString()) - return d->unboundData.toString() == other.d->value.stringValue()->toQString(); + if (ov->isString()) + return d->unboundData.toString() == ov->stringValue()->toQString(); return false; } - if (other.d->value.isEmpty()) + if (!ov) return other.strictlyEquals(*this); - return RuntimeHelpers::strictEqual(QV4::ValueRef(d), QV4::ValueRef(other.d)); + return RuntimeHelpers::strictEqual(*v, *ov); } /*! @@ -876,12 +960,12 @@ bool QJSValue::strictlyEquals(const QJSValue& other) const */ QJSValue QJSValue::property(const QString& name) const { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); if (!engine) return QJSValue(); - QV4::Scope scope(engine); - ScopedObject o(scope, d->value); + QV4::Scope scope(engine); + ScopedObject o(scope, d->persistent.value()); if (!o) return QJSValue(); @@ -892,8 +976,8 @@ QJSValue QJSValue::property(const QString& name) const s->makeIdentifier(); QV4::ScopedValue result(scope, o->get(s)); - if (d->engine->hasException) - result = d->engine->catchException(); + if (engine->hasException) + result = engine->catchException(); return new QJSValuePrivate(engine, result); } @@ -912,18 +996,18 @@ QJSValue QJSValue::property(const QString& name) const */ QJSValue QJSValue::property(quint32 arrayIndex) const { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); if (!engine) return QJSValue(); QV4::Scope scope(engine); - ScopedObject o(scope, d->value); + ScopedObject o(scope, d->persistent.value()); if (!o) return QJSValue(); QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex)); - if (d->engine->hasException) - d->engine->catchException(); + if (engine->hasException) + engine->catchException(); return new QJSValuePrivate(engine, result); } @@ -940,12 +1024,12 @@ QJSValue QJSValue::property(quint32 arrayIndex) const */ void QJSValue::setProperty(const QString& name, const QJSValue& value) { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); if (!engine) return; Scope scope(engine); - ScopedObject o(scope, d->value); + ScopedObject o(scope, d->persistent.value()); if (!o) return; @@ -964,8 +1048,8 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value) s->makeIdentifier(); QV4::ScopedValue v(scope, value.d->getValue(engine)); o->put(s, v); - if (d->engine->hasException) - d->engine->catchException(); + if (engine->hasException) + engine->catchException(); } /*! @@ -982,12 +1066,12 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value) */ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); if (!engine) return; Scope scope(engine); - ScopedObject o(scope, d->value); + ScopedObject o(scope, d->persistent.value()); if (!o) return; @@ -996,8 +1080,8 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) o->putIndexed(arrayIndex, v); else o->put(engine->id_uintMax, v); - if (d->engine->hasException) - d->engine->catchException(); + if (engine->hasException) + engine->catchException(); } /*! @@ -1022,16 +1106,16 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) */ bool QJSValue::deleteProperty(const QString &name) { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); Scope scope(engine); - ScopedObject o(scope, d->value.asObject()); + ScopedObject o(scope, d->persistent.value()); if (!o) return false; ScopedString s(scope, engine->newString(name)); bool b = o->deleteProperty(s); - if (d->engine->hasException) - d->engine->catchException(); + if (engine->hasException) + engine->catchException(); return b; } @@ -1043,12 +1127,12 @@ bool QJSValue::deleteProperty(const QString &name) */ bool QJSValue::hasProperty(const QString &name) const { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); if (!engine) return false; Scope scope(engine); - ScopedObject o(scope, d->value); + ScopedObject o(scope, d->persistent.value()); if (!o) return false; @@ -1064,12 +1148,12 @@ bool QJSValue::hasProperty(const QString &name) const */ bool QJSValue::hasOwnProperty(const QString &name) const { - ExecutionEngine *engine = d->engine; + ExecutionEngine *engine = d->engine(); if (!engine) return false; Scope scope(engine); - ScopedObject o(scope, d->value); + ScopedObject o(scope, d->persistent.value()); if (!o) return false; @@ -1089,10 +1173,11 @@ bool QJSValue::hasOwnProperty(const QString &name) const */ QObject *QJSValue::toQObject() const { - if (!d->engine) + ExecutionEngine *engine = d->engine(); + if (!engine) return 0; - QV4::Scope scope(d->engine); - QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, d->value); + QV4::Scope scope(engine); + QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, d->persistent.value()); if (!wrapper) return 0; @@ -1108,10 +1193,12 @@ QObject *QJSValue::toQObject() const */ QDateTime QJSValue::toDateTime() const { - QV4::DateObject *date = d->value.asDateObject(); - if (!date) - return QDateTime(); - return date->toQDateTime(); + if (!d->persistent.isEmpty()) { + QV4::DateObject *date = d->persistent.valueRef()->asDateObject(); + if (date) + return date->toQDateTime(); + } + return QDateTime(); } /*! @@ -1120,7 +1207,7 @@ QDateTime QJSValue::toDateTime() const */ bool QJSValue::isDate() const { - return d->value.asDateObject(); + return !d->persistent.isEmpty() && d->persistent.valueRef()->asDateObject(); } /*! @@ -1129,7 +1216,7 @@ bool QJSValue::isDate() const */ bool QJSValue::isRegExp() const { - return d->value.as<RegExpObject>(); + return !d->persistent.isEmpty() && d->persistent.valueRef()->as<RegExpObject>(); } /*! @@ -1143,7 +1230,7 @@ bool QJSValue::isRegExp() const */ bool QJSValue::isQObject() const { - return d->value.as<QV4::QObjectWrapper>() != 0; + return !d->persistent.isEmpty() && d->persistent.valueRef()->as<QV4::QObjectWrapper>() != 0; } QT_END_NAMESPACE diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h index 43a3a74e38..3d7afdbd75 100644 --- a/src/qml/jsapi/qjsvalue_p.h +++ b/src/qml/jsapi/qjsvalue_p.h @@ -52,6 +52,8 @@ #include <private/qv4engine_p.h> #include <private/qv4object_p.h> #include <private/qflagpointer_p.h> +#include <private/qv4mm_p.h> +#include <private/qv4persistent_p.h> QT_BEGIN_NAMESPACE @@ -59,30 +61,60 @@ QT_BEGIN_NAMESPACE \internal \class QJSValuePrivate */ -class Q_QML_PRIVATE_EXPORT QJSValuePrivate : public QV4::PersistentValuePrivate +class Q_QML_PRIVATE_EXPORT QJSValuePrivate { public: - QJSValuePrivate(QV4::ExecutionEngine *engine, const QV4::ValueRef v) - : PersistentValuePrivate(v.asReturnedValue(), engine) + QJSValuePrivate() + : refcount(1) + {} + QJSValuePrivate(QV4::ExecutionEngine *e, const QV4::ValueRef v) + : refcount(1), + persistent(e, v) { - Q_ASSERT(!value.isEmpty()); + Q_ASSERT(!v->isEmpty()); } - QJSValuePrivate(QV4::ReturnedValue v) - : PersistentValuePrivate(v) + QJSValuePrivate(QV4::ExecutionEngine *e, QV4::ReturnedValue v) + : refcount(1), + persistent(e, v) { - Q_ASSERT(!value.isEmpty()); } - QJSValuePrivate(const QString &s) - : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue()), - unboundData(s) + explicit QJSValuePrivate(const QVariant &v) + : refcount(1), + unboundData(v) { } + bool checkEngine(QV4::ExecutionEngine *e) { + if (persistent.isEmpty()) + getValue(e); + return persistent.engine() == e; + } + QV4::ReturnedValue getValue(QV4::ExecutionEngine *e); static QJSValuePrivate *get(const QJSValue &v) { return v.d; } + QV4::ExecutionEngine *engine() const { return persistent.engine(); } + + void ref() { ++refcount; } + void deref() { + if (!--refcount) + delete this; + } + + QV4::Value *valueForData(QV4::Value *scratch) const { + QV4::Value *v = persistent.valueRef(); + if (v) + return v; + *scratch = primitiveValueForUnboundData(); + return (scratch->isEmpty() ? 0 : scratch); + } + QV4::Value primitiveValueForUnboundData() const; + int refcount; + QV4::PersistentValue persistent; QVariant unboundData; +private: + QJSValuePrivate(QV4::ReturnedValue v) Q_DECL_EQ_DELETE; }; QT_END_NAMESPACE diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index c74a5d2d76..e23bd5d763 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -46,12 +46,12 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) , nextIndex(UINT_MAX) { QJSValuePrivate *jsp = QJSValuePrivate::get(value); - QV4::ExecutionEngine *e = jsp->engine; + QV4::ExecutionEngine *e = jsp->persistent.engine(); if (!e) return; QV4::Scope scope(e); - QV4::ScopedObject o(scope, jsp->value); + QV4::ScopedObject o(scope, jsp->persistent.value()); iterator.set(e, e->newForEachIteratorObject(o)); currentName = (QV4::String *)0; @@ -123,7 +123,8 @@ QJSValueIterator::~QJSValueIterator() */ bool QJSValueIterator::hasNext() const { - if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + QV4::Value *val = QJSValuePrivate::get(d_ptr->value)->persistent.valueRef(); + if (!val || !val->isObject()) return false; return !!d_ptr->nextName || d_ptr->nextIndex != UINT_MAX; } @@ -138,7 +139,8 @@ bool QJSValueIterator::hasNext() const */ bool QJSValueIterator::next() { - if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + QV4::Value *val = QJSValuePrivate::get(d_ptr->value)->persistent.valueRef(); + if (!val || !val->isObject()) return false; d_ptr->currentName = d_ptr->nextName; d_ptr->currentIndex = d_ptr->nextIndex; @@ -164,7 +166,8 @@ bool QJSValueIterator::next() */ QString QJSValueIterator::name() const { - if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + QV4::Value *val = QJSValuePrivate::get(d_ptr->value)->persistent.valueRef(); + if (!val || !val->isObject()) return QString(); if (!!d_ptr->currentName) return d_ptr->currentName->toQString(); @@ -186,7 +189,7 @@ QJSValue QJSValueIterator::value() const if (!engine) return QJSValue(); QV4::Scope scope(engine); - QV4::ScopedObject obj(scope, QJSValuePrivate::get(d_ptr->value)->value); + QV4::ScopedObject obj(scope, QJSValuePrivate::get(d_ptr->value)->persistent.value()); if (!obj) return QJSValue(); @@ -216,13 +219,13 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) d_ptr->nextName = (QV4::String *)0; QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); if (!v4) { - d_ptr->iterator.set(v4, QV4::Encode::undefined()); + d_ptr->iterator.clear(); return *this; } QJSValuePrivate *jsp = QJSValuePrivate::get(object); QV4::Scope scope(v4); - QV4::ScopedObject o(scope, jsp->value); + QV4::ScopedObject o(scope, jsp->persistent.value()); d_ptr->iterator.set(v4, v4->newForEachIteratorObject(o)); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; |