From e9ffb5b0918e800edfba6b697c7a14ef6c7fa8e1 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Wed, 26 Aug 2009 13:57:29 +0200 Subject: fix performance issue with QScriptValue::propertyFlags() Calling QScriptEngine::toStringHandle() is dead slow, so don't call it; use JSC::Identifier directly. This is the same issue as was fixed for setProperty() in commit a8574172dd5e6bc11cf6f69b6fad5a063549e88d. --- src/script/api/qscriptvalue.cpp | 65 ++++++++++++---------- src/script/api/qscriptvalue_p.h | 2 + tests/auto/qscriptvalue/tst_qscriptvalue.cpp | 1 + tests/benchmarks/qscriptvalue/tst_qscriptvalue.cpp | 12 ++++ 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index 1d08676..984ad1b 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -393,6 +393,37 @@ void QScriptValuePrivate::setProperty(const JSC::Identifier &id, const QScriptVa } } +QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const JSC::Identifier &id, + const QScriptValue::ResolveFlags &mode) const +{ + JSC::ExecState *exec = engine->currentFrame; + JSC::JSObject *object = JSC::asObject(jscValue); + unsigned attribs = 0; + if (!object->getPropertyAttributes(exec, id, attribs)) { + if ((mode & QScriptValue::ResolvePrototype) && object->prototype() && object->prototype().isObject()) { + QScriptValue proto = engine->scriptValueFromJSCValue(object->prototype()); + return QScriptValuePrivate::get(proto)->propertyFlags(id, mode); + } + return 0; + } + QScriptValue::PropertyFlags result = 0; + if (attribs & JSC::ReadOnly) + result |= QScriptValue::ReadOnly; + if (attribs & JSC::DontEnum) + result |= QScriptValue::SkipInEnumeration; + if (attribs & JSC::DontDelete) + result |= QScriptValue::Undeletable; + //We cannot rely on attribs JSC::Setter/Getter because they are not necesserly set by JSC (bug?) + if (attribs & JSC::Getter || !object->lookupGetter(exec, id).isUndefinedOrNull()) + result |= QScriptValue::PropertyGetter; + if (attribs & JSC::Setter || !object->lookupSetter(exec, id).isUndefinedOrNull()) + result |= QScriptValue::PropertySetter; + if (attribs & QScript::QObjectMemberAttribute) + result |= QScriptValue::QObjectMember; + result |= QScriptValue::PropertyFlag(attribs & QScriptValue::UserRange); + return result; +} + QVariant &QScriptValuePrivate::variantValue() const { Q_ASSERT(jscValue.isObject(&QScriptObject::info)); @@ -1817,9 +1848,11 @@ void QScriptValue::setProperty(const QScriptString &name, QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString &name, const ResolveFlags &mode) const { - if (!isObject()) + Q_D(const QScriptValue); + if (!d || !d->isJSC() || !d->jscValue.isObject()) return 0; - return propertyFlags(engine()->toStringHandle(name), mode); + JSC::ExecState *exec = d->engine->currentFrame; + return d->propertyFlags(JSC::Identifier(exec, name), mode); } @@ -1835,33 +1868,9 @@ QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString &nam const ResolveFlags &mode) const { Q_D(const QScriptValue); - if (!isObject()) - return 0; - JSC::ExecState *exec = d->engine->currentFrame; - JSC::JSObject *object = JSC::asObject(d->jscValue); - JSC::Identifier id = name.d_ptr->identifier; - unsigned attribs = 0; - if (!object->getPropertyAttributes(exec, id, attribs)) { - if ((mode & QScriptValue::ResolvePrototype) && object->prototype()) - return d->engine->scriptValueFromJSCValue(object->prototype()).propertyFlags(name, mode); + if (!d || !d->isJSC() || !d->jscValue.isObject() || !name.isValid()) return 0; - } - QScriptValue::PropertyFlags result = 0; - if (attribs & JSC::ReadOnly) - result |= QScriptValue::ReadOnly; - if (attribs & JSC::DontEnum) - result |= QScriptValue::SkipInEnumeration; - if (attribs & JSC::DontDelete) - result |= QScriptValue::Undeletable; - //We cannot rely on attribs JSC::Setter/Getter because they are not necesserly set by JSC (bug?) - if (attribs & JSC::Getter || !object->lookupGetter(exec, id).isUndefinedOrNull()) - result |= QScriptValue::PropertyGetter; - if (attribs & JSC::Setter || !object->lookupSetter(exec, id).isUndefinedOrNull()) - result |= QScriptValue::PropertySetter; - if (attribs & QScript::QObjectMemberAttribute) - result |= QScriptValue::QObjectMember; - result |= QScriptValue::PropertyFlag(attribs & QScriptValue::UserRange); - return result; + return d->propertyFlags(name.d_ptr->identifier, mode); } /*! diff --git a/src/script/api/qscriptvalue_p.h b/src/script/api/qscriptvalue_p.h index 3e952af..c440013 100644 --- a/src/script/api/qscriptvalue_p.h +++ b/src/script/api/qscriptvalue_p.h @@ -104,6 +104,8 @@ public: inline QScriptValue property(const QString &, int resolveMode) const; void setProperty(const JSC::Identifier &id, const QScriptValue &value, const QScriptValue::PropertyFlags &flags); + QScriptValue::PropertyFlags propertyFlags( + const JSC::Identifier &id, const QScriptValue::ResolveFlags &mode) const; void detachFromEngine(); diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp index 3f231f2..e712017 100644 --- a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp +++ b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp @@ -2106,6 +2106,7 @@ void tst_QScriptValue::getSetProperty() object.setProperty(foo, num); QVERIFY(object.property(foo).strictlyEquals(num)); QVERIFY(object.property("foo").strictlyEquals(num)); + QVERIFY(object.propertyFlags(foo) == 0); } void tst_QScriptValue::getSetPrototype() diff --git a/tests/benchmarks/qscriptvalue/tst_qscriptvalue.cpp b/tests/benchmarks/qscriptvalue/tst_qscriptvalue.cpp index 904674e..b637591 100644 --- a/tests/benchmarks/qscriptvalue/tst_qscriptvalue.cpp +++ b/tests/benchmarks/qscriptvalue/tst_qscriptvalue.cpp @@ -68,6 +68,7 @@ private slots: void toQObject(); void property(); void setProperty(); + void propertyFlags(); }; tst_QScriptValue::tst_QScriptValue() @@ -189,5 +190,16 @@ void tst_QScriptValue::setProperty() } } +void tst_QScriptValue::propertyFlags() +{ + QScriptEngine engine; + QScriptValue obj = engine.newObject(); + QString propertyName = QString::fromLatin1("foo"); + obj.setProperty(propertyName, 123, QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly); + QBENCHMARK { + (void)obj.propertyFlags(propertyName); + } +} + QTEST_MAIN(tst_QScriptValue) #include "tst_qscriptvalue.moc" -- cgit v0.12