From dff7f0593d86e90eb14c805a96ebbda778f45a82 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 18:13:04 +1000 Subject: Improve script lookup caching --- demos/declarative/samegame/content/samegame.js | 3 + src/declarative/qml/qml.pri | 10 +- src/declarative/qml/qmlcompiler.cpp | 20 +- src/declarative/qml/qmlcompiler_p.h | 4 +- src/declarative/qml/qmlcontext.cpp | 47 ++-- src/declarative/qml/qmlcontext_p.h | 10 +- src/declarative/qml/qmlcontextscriptclass.cpp | 190 +++++++++++++++++ src/declarative/qml/qmlcontextscriptclass_p.h | 89 ++++++++ src/declarative/qml/qmlengine.cpp | 264 +---------------------- src/declarative/qml/qmlengine_p.h | 62 +----- src/declarative/qml/qmlinstruction_p.h | 2 +- src/declarative/qml/qmlintegercache.cpp | 108 ++++++++++ src/declarative/qml/qmlintegercache_p.h | 103 +++++++++ src/declarative/qml/qmlmetaproperty.cpp | 2 +- src/declarative/qml/qmlobjectscriptclass.cpp | 283 +++++++++++++++++++++++++ src/declarative/qml/qmlobjectscriptclass_p.h | 98 +++++++++ src/declarative/qml/qmlpropertycache.cpp | 20 +- src/declarative/qml/qmlpropertycache_p.h | 37 +++- src/declarative/qml/qmlvme.cpp | 4 +- src/script/api/qscriptvalue.cpp | 5 + src/script/bridge/qscriptdeclarativeclass.cpp | 13 ++ src/script/bridge/qscriptdeclarativeclass_p.h | 2 + 22 files changed, 1021 insertions(+), 355 deletions(-) create mode 100644 src/declarative/qml/qmlcontextscriptclass.cpp create mode 100644 src/declarative/qml/qmlcontextscriptclass_p.h create mode 100644 src/declarative/qml/qmlintegercache.cpp create mode 100644 src/declarative/qml/qmlintegercache_p.h create mode 100644 src/declarative/qml/qmlobjectscriptclass.cpp create mode 100644 src/declarative/qml/qmlobjectscriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index e42b7cc..4a9179b 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -38,6 +38,7 @@ function initBoard() scoreName.forceClose(); dialog.forceClose(); + var a = new Date(); //Initialize Board board = new Array(maxIndex); gameCanvas.score = 0; @@ -48,6 +49,8 @@ function initBoard() } } timer = new Date(); + + print(timer.valueOf() - a.valueOf()); } var fillFound;//Set after a floodFill call to the number of tiles found diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 216adb1..1a6dad3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -35,7 +35,10 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ qml/qmlwatcher.cpp \ - qml/qmlpropertycache.cpp + qml/qmlpropertycache.cpp \ + qml/qmlintegercache.cpp \ + qml/qmlobjectscriptclass.cpp \ + qml/qmlcontextscriptclass.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -88,7 +91,10 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlsqldatabase_p.h \ qml/qmetaobjectbuilder_p.h \ qml/qmlwatcher_p.h \ - qml/qmlpropertycache_p.h + qml/qmlpropertycache_p.h \ + qml/qmlintegercache_p.h \ + qml/qmlobjectscriptclass_p.h \ + qml/qmlcontextscriptclass_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 0b4ac20..5cb2158 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -633,7 +633,7 @@ void QmlCompiler::compileTree(Object *tree) init.line = 0; init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; - init.init.idSize = compileState.ids.count(); + init.init.contextCache = genContextCache(); output->bytecode << init; genObject(tree); @@ -964,7 +964,7 @@ void QmlCompiler::genComponent(QmlParser::Object *obj) init.type = QmlInstruction::Init; init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; - init.init.idSize = compileState.ids.count(); + init.init.contextCache = genContextCache(); init.line = obj->location.start.line; output->bytecode << init; @@ -2263,6 +2263,22 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, output->bytecode << store; } +int QmlCompiler::genContextCache() +{ + if (compileState.ids.count() == 0) + return -1; + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + for (QHash::ConstIterator iter = compileState.ids.begin(); + iter != compileState.ids.end(); + ++iter) + cache->add(iter.key(), (*iter)->idIndex); + + output->contextCaches.append(cache); + return output->contextCaches.count() - 1; +} + bool QmlCompiler::completeComponentBuild() { for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 677aba7..1cb66c7 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -63,6 +63,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -111,6 +112,7 @@ public: QList bytecode; QList programs; QList propertyCaches; + QList contextCaches; void dumpInstructions(); private: @@ -232,7 +234,7 @@ private: QmlParser::Property *prop, QmlParser::Object *obj, QmlParser::Property *valueTypeProperty = 0); - + int genContextCache(); int componentTypeRef(); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 97ab375..1c9d177 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE QmlContextPrivate::QmlContextPrivate() -: parent(0), engine(0), isInternal(false), notifyIndex(-1), +: parent(0), engine(0), isInternal(false), propertyNames(0), notifyIndex(-1), highPriorityCount(0), expressions(0), idValues(0), idValueCount(0) { } @@ -103,8 +103,8 @@ void QmlContextPrivate::init() //set scope chain QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptValue scopeObj = - scriptEngine->newObject(QmlEnginePrivate::get(engine)->contextClass, scriptEngine->newVariant(QVariant::fromValue((QObject*)q))); + QScriptValue scopeObj = QmlEnginePrivate::get(engine)->contextClass->newContext(q); + //### no longer need to push global object once we switch to JSC (test with objects added to globalObject) //if (parent) // scopeChain = parent->d_func()->scopeChain; @@ -304,6 +304,9 @@ QmlContext::~QmlContext() d->contextObjects.clear(); delete [] d->idValues; + + if (d->propertyNames) + d->propertyNames->release(); } void QmlContextPrivate::invalidateEngines() @@ -361,13 +364,16 @@ void QmlContext::setContextProperty(const QString &name, const QVariant &value) QObject *o = QmlMetaType::toQObject(value); setContextProperty(name, o); } else { - QHash::ConstIterator iter = d->propertyNames.find(name); - if(iter == d->propertyNames.end()) { - d->propertyNames.insert(name, d->idValueCount + d->propertyValues.count()); + + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + + int idx = d->propertyNames->value(name); + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); d->propertyValues.append(value); } else { - d->propertyValues[*iter] = value; - QMetaObject::activate(this, *iter + d->notifyIndex, 0); + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); } } } @@ -380,15 +386,19 @@ void QmlContextPrivate::setIdProperty(const QString &name, int idx, notifyIndex = q->metaObject()->methodCount(); } - propertyNames.insert(name, idx); + propertyNames->add(name, idx); idValues[idx].priv = this; idValues[idx] = obj; } -void QmlContextPrivate::setIdPropertyCount(int count) +void QmlContextPrivate::setIdPropertyData(QmlIntegerCache *data) { - idValues = new ContextGuard[count]; - idValueCount = count; + Q_ASSERT(!propertyNames); + propertyNames = data; + propertyNames->addref(); + + idValueCount = data->count(); + idValues = new ContextGuard[idValueCount]; } /*! @@ -402,14 +412,15 @@ void QmlContext::setContextProperty(const QString &name, QObject *value) if (d->notifyIndex == -1) d->notifyIndex = this->metaObject()->methodCount(); - QHash::ConstIterator iter = d->propertyNames.find(name); - if(iter == d->propertyNames.end()) { - d->propertyNames.insert(name, d->idValueCount + d->propertyValues.count()); + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + int idx = d->propertyNames->value(name); + + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); d->propertyValues.append(QVariant::fromValue(value)); } else { - int idx = *iter; - d->propertyValues[*iter] = QVariant::fromValue(value); - QMetaObject::activate(this, *iter + d->notifyIndex, 0); + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); } } diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index b305408..64faa6d 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -61,6 +61,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -82,7 +83,8 @@ public: QmlEngine *engine; bool isInternal; - QHash propertyNames; + QmlIntegerCache *propertyNames; +// QHash propertyNames; QList propertyValues; int notifyIndex; @@ -125,9 +127,13 @@ public: ContextGuard *idValues; int idValueCount; void setIdProperty(const QString &, int, QObject *); - void setIdPropertyCount(int); + void setIdPropertyData(QmlIntegerCache *); void destroyed(ContextGuard *); + static QmlContextPrivate *get(QmlContext *context) { + return static_cast(QObjectPrivate::get(context)); + } + // Only used for debugging QList > instances; }; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp new file mode 100644 index 0000000..baea60a --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcontextscriptclass_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +struct ContextData { + ContextData(QmlContext *c) : context(c) {} + QGuard context; +}; + +/* + The QmlContextScriptClass handles property access for a QmlContext + via QtScript. + */ +QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), + lastPropertyIndex(-1), lastDefaultObject(-1) +{ +} + +QmlContextScriptClass::~QmlContextScriptClass() +{ +} + +QScriptValue QmlContextScriptClass::newContext(QmlContext *context) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, (Object)new ContextData(context)); +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + QmlContext *bindContext = ((ContextData *)object)->context.data(); + if (!bindContext) + return 0; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + lastPropertyIndex = -1; + lastDefaultObject = -1; + + lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; + if (lastPropertyIndex != -1) + return QScriptClass::HandlesReadAccess; + + // ### Check for attached properties +#if 0 + QmlType *type = 0; ImportedNamespace *ns = 0; + if (currentExpression && bindContext == currentExpression->context() && + propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { + + if (type || ns) { + // Must be either an attached property, or an enum + resolveData.object = bindContext->d_func()->defaultObjects.first(); + resolveData.type = type; + resolveData.ns = ns; + return QScriptClass::HandlesReadAccess; + } + + } +#endif + + for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags); + + if (rv) { + lastDefaultObject = ii; + return rv; + } + } + + return 0; +} + +QScriptValue QmlContextScriptClass::property(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + + Q_ASSERT(lastPropertyIndex != -1 || lastDefaultObject != -1); + + QmlContext *bindContext = ((ContextData *)object)->context.data(); + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + + // ### Check for attached properties +#if 0 + if (resolveData.type || resolveData.ns) { + QmlTypeNameBridge tnb = { + resolveData.object, + resolveData.type, + resolveData.ns + }; + return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); + } +#endif + + if (lastPropertyIndex != -1) { + + QScriptValue rv; + if (lastPropertyIndex < cp->idValueCount) { + rv = ep->objectClass->newQObject(cp->idValues[lastPropertyIndex].data()); + } else { + QVariant value = cp->propertyValues.at(lastPropertyIndex); + if (QmlMetaType::isObject(value.userType())) { + rv = ep->objectClass->newQObject(QmlMetaType::toQObject(value)); + } else { + // ### Shouldn't this be qScriptValueFromValue() + rv = ep->scriptEngine.newVariant(value); + } + } + + ep->capturedProperties << + QmlEnginePrivate::CapturedProperty(bindContext, -1, + lastPropertyIndex + cp->notifyIndex); + + return rv; + } else { + + // Default object property + return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); + + } +} + +void QmlContextScriptClass::setProperty(const Object &object, const Identifier &name, + const QScriptValue &value) +{ + Q_ASSERT(lastDefaultObject != -1); + + QmlContext *bindContext = ((ContextData *)object)->context.data(); + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h new file mode 100644 index 0000000..9ef090d --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXTSCRIPTCLASS_P_H +#define QMLCONTEXTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlContext; +class QmlContextScriptClass : public QScriptDeclarativeClass +{ +public: + QmlContextScriptClass(QmlEngine *); + ~QmlContextScriptClass(); + + QScriptValue newContext(QmlContext *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + +private: + QmlEngine *engine; + + int lastPropertyIndex; + int lastDefaultObject; + + uint m_id; +}; + +QT_END_NAMESPACE + +#endif // QMLCONTEXTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 757670b..d680fa1 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -193,8 +193,6 @@ QmlEnginePrivate::~QmlEnginePrivate() contextClass = 0; delete objectClass; objectClass = 0; - delete objectClass2; - objectClass2 = 0; delete valueTypeClass; valueTypeClass = 0; delete typeNameClass; @@ -242,7 +240,6 @@ void QmlEnginePrivate::init() scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); - objectClass2 = new QScriptDeclarativeClass(&scriptEngine); valueTypeClass = new QmlValueTypeScriptClass(q); typeNameClass = new QmlTypeNameScriptClass(q); rootContext = new QmlContext(q,true); @@ -288,95 +285,6 @@ struct QmlValueTypeReference { }; Q_DECLARE_METATYPE(QmlValueTypeReference); -//////////////////////////////////////////////////////////////////// -QScriptClass::QueryFlags -QmlEnginePrivate::queryContext(const QString &propName, uint *id, - QmlContext *bindContext) -{ - resolveData.safetyCheckId++; - *id = resolveData.safetyCheckId; - resolveData.clear(); - - QHash::Iterator contextProperty = - bindContext->d_func()->propertyNames.find(propName); - - if (contextProperty != bindContext->d_func()->propertyNames.end()) { - - resolveData.context = bindContext; - resolveData.contextIndex = *contextProperty; - - return QScriptClass::HandlesReadAccess; - } - - QmlType *type = 0; ImportedNamespace *ns = 0; - if (currentExpression && bindContext == currentExpression->context() && - propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { - - if (type || ns) { - // Must be either an attached property, or an enum - resolveData.object = bindContext->d_func()->defaultObjects.first(); - resolveData.type = type; - resolveData.ns = ns; - return QScriptClass::HandlesReadAccess; - } - - } - - QScriptClass::QueryFlags rv = 0; - for (int ii = 0; !rv && ii < bindContext->d_func()->defaultObjects.count(); ++ii) { - rv = queryObject(propName, id, - bindContext->d_func()->defaultObjects.at(ii)); - } - - return rv; -} - -QScriptValue QmlEnginePrivate::propertyContext(const QScriptString &name, uint id) -{ - Q_ASSERT(id == resolveData.safetyCheckId); - - if (resolveData.type || resolveData.ns) { - QmlTypeNameBridge tnb = { - resolveData.object, - resolveData.type, - resolveData.ns - }; - return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); - } else if (resolveData.context) { - QmlContext *bindContext = resolveData.context; - QmlContextPrivate *contextPrivate = bindContext->d_func(); - int index = resolveData.contextIndex; - - QScriptValue rv; - if (index < contextPrivate->idValueCount) { - rv = scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(contextPrivate->idValues[index].data()))); - } else { - QVariant value = contextPrivate->propertyValues.at(index); - if (QmlMetaType::isObject(value.userType())) { - rv = scriptEngine.newObject(objectClass, scriptEngine.newVariant(value)); - } else { - rv = scriptEngine.newVariant(value); - } - } - capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, -1, index + contextPrivate->notifyIndex); - return rv; - - } else { - - return propertyObject(name, resolveData.object, id); - - } - - return QScriptValue(); -} - -void QmlEnginePrivate::setPropertyContext(const QScriptValue &value, uint id) -{ - // As context properties cannot be written, we can assume that the - // write is a object property write - setPropertyObject(value, id); -} - void QmlEnginePrivate::setPropertyObject(const QScriptValue &value, uint id) { Q_ASSERT(id == resolveData.safetyCheckId); @@ -430,7 +338,7 @@ QmlEnginePrivate::queryObject(const QString &propName, return rv; } -QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, +QScriptValue QmlEnginePrivate::propertyObject(const QString &propName, QObject *obj, uint id) { Q_ASSERT(id == resolveData.safetyCheckId); @@ -461,7 +369,7 @@ QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, if (!varobj) varobj = qvariant_cast(var); if (varobj) { - return scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(varobj))); + return objectClass->newQObject(varobj); } else { return qScriptValueFromValue(&scriptEngine, var); } @@ -784,8 +692,8 @@ void QmlDeclarativeData::setBindingBit(QObject *obj, int bit) QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object, QmlEngine* engine) { - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return scriptEngine->newObject(engine->d_func()->objectClass, scriptEngine->newQObject(object, QScriptEngine::AutoOwnership)); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + return enginePriv->objectClass->newQObject(object); } /*! @@ -901,7 +809,7 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi QUrl url; if(ctxt->argumentCount() > 2) url = QUrl(ctxt->argument(2).toString()); - QObject *parentArg = ctxt->argument(1).data().toQObject(); + QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); QmlContext *qmlCtxt = qmlContext(parentArg); url = qmlCtxt->resolvedUrl(url); QmlComponent component(activeEngine, qml.toUtf8(), url); @@ -1138,13 +1046,15 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) QmlEnginePrivate *ep = static_cast(QObjectPrivate::get(engine)); + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == ep->objectClass) + return QVariant::fromValue(ep->objectClass->toQObject(val)); + else if (dc == ep->contextClass) + return QVariant(); + QScriptClass *sc = val.scriptClass(); if (!sc) { return val.toVariant(); - } else if (sc == ep->contextClass) { - return QVariant(); - } else if (sc == ep->objectClass) { - return QVariant::fromValue(val.data().toQObject()); } else if (sc == ep->valueTypeClass) { QmlValueTypeReference ref = qvariant_cast(val.data().toVariant()); @@ -1160,56 +1070,6 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) } ///////////////////////////////////////////////////////////// -/* - The QmlContextScriptClass handles property access for a QmlContext - via QtScript. - */ -QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) - : QmlScriptClass(bindEngine) -{ -} - -QmlContextScriptClass::~QmlContextScriptClass() -{ -} - -QScriptClass::QueryFlags -QmlContextScriptClass::queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - QmlContext *bindContext = - static_cast(object.data().toQObject()); - - QString propName = name.toString(); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - return ep->queryContext(propName, id, bindContext); -} - -QScriptValue QmlContextScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - Q_UNUSED(object); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - return ep->propertyContext(name, id); -} - -void QmlContextScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(object); - Q_UNUSED(name); - - QmlEnginePrivate::get(engine)->setPropertyContext(value, id); -} - -///////////////////////////////////////////////////////////// QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *engine) : QmlScriptClass(engine), object(0), type(0) { @@ -1365,108 +1225,6 @@ void QmlValueTypeScriptClass::setProperty(QScriptValue &object, ref.type->write(ref.object, ref.property); } -///////////////////////////////////////////////////////////// -/* - The QmlObjectScriptClass handles property access for QObjects - via QtScript. It is also used to provide a more useful API in - QtScript for QML. - */ - -QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - QString ret = QLatin1String("Qml Object, "); - if(obj){ - //###Should this be designer or developer details? Dev for now. - //TODO: Can we print the id too? - ret += QLatin1String("\""); - ret += obj->objectName(); - ret += QLatin1String("\" "); - ret += QLatin1String(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - ret += QLatin1String(")"); - }else{ - ret += QLatin1String("null"); - } - return engine->newVariant(ret); -} - -QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - QTimer::singleShot(delay, obj, SLOT(deleteLater())); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); - } - return engine->nullValue(); -} - -QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) - : QmlScriptClass(bindEngine) -{ - engine = bindEngine; - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); - prototypeObject = scriptEngine->newObject(); - prototypeObject.setProperty(QLatin1String("toStr"),//TODO: Why won't toString work? - scriptEngine->newFunction(QmlObjectToString)); - prototypeObject.setProperty(QLatin1String("destroy"), - scriptEngine->newFunction(QmlObjectDestroy)); -} - -QmlObjectScriptClass::~QmlObjectScriptClass() -{ -} - -QScriptValue QmlObjectScriptClass::prototype() const -{ - return prototypeObject; -} - -QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - QObject *obj = object.data().toQObject(); - QueryFlags rv = 0; - QString propName = name.toString(); - - if (obj) - rv = QmlEnginePrivate::get(engine)->queryObject(propName, id, obj); - - return rv; -} - -QScriptValue QmlObjectScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - QObject *obj = object.data().toQObject(); - - QScriptValue rv = - QmlEnginePrivate::get(engine)->propertyObject(name, obj, id); - if (rv.isValid()) - return rv; - - return QScriptValue(); -} - -void QmlObjectScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(name); - Q_UNUSED(object); - QmlEnginePrivate::get(engine)->setPropertyObject(value, id); -} - - struct QmlEnginePrivate::ImportedNamespace { QStringList urls; QList majversions; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 68019e2..764cc6c 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -73,6 +73,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -100,13 +102,9 @@ public: void init(); - QScriptClass::QueryFlags queryContext(const QString &name, uint *id, - QmlContext *); - QScriptValue propertyContext(const QScriptString &propName, uint id); - void setPropertyContext(const QScriptValue &, uint id); QScriptClass::QueryFlags queryObject(const QString &name, uint *id, QObject *); - QScriptValue propertyObject(const QScriptString &propName, QObject *, + QScriptValue propertyObject(const QString &propName, QObject *, uint id = 0); void setPropertyObject(const QScriptValue &, uint id); @@ -151,7 +149,6 @@ public: } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; - QScriptDeclarativeClass *objectClass2; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; // Used by DOM Core 3 API @@ -215,6 +212,7 @@ public: // ### Fixme typedef QHash, bool> FunctionCache; FunctionCache functionCache; + QHash propertyCache; QmlPropertyCache *cache(QObject *obj) { Q_Q(QmlEngine); @@ -285,19 +283,6 @@ public: class QmlScriptClass : public QScriptClass { public: - enum ClassId - { - InvalidId = -1, - - FunctionId = 0x80000000, - VariantPropertyId = 0x40000000, - PropertyId = 0x00000000, - - ClassIdMask = 0xC0000000, - - ClassIdSelectorMask = 0x3F000000, - }; - QmlScriptClass(QmlEngine *); static QVariant toVariant(QmlEngine *, const QScriptValue &); @@ -305,45 +290,6 @@ protected: QmlEngine *engine; }; -class QmlContextScriptClass : public QmlScriptClass -{ -public: - QmlContextScriptClass(QmlEngine *); - ~QmlContextScriptClass(); - - virtual QueryFlags queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id); - virtual QScriptValue property(const QScriptValue &object, - const QScriptString &name, - uint id); - virtual void setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value); -}; - -class QmlObjectScriptClass : public QmlScriptClass -{ -public: - QmlObjectScriptClass(QmlEngine *); - ~QmlObjectScriptClass(); - - virtual QScriptValue prototype () const; - QScriptValue prototypeObject; - - virtual QueryFlags queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id); - virtual QScriptValue property(const QScriptValue &object, - const QScriptString &name, - uint id); - virtual void setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value); -}; - class QmlTypeNameScriptClass : public QmlScriptClass { public: diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index e62bfdf..38b3191 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -165,7 +165,7 @@ public: struct { int bindingsSize; int parserStatusSize; - int idSize; + int contextCache; } init; struct { int type; diff --git a/src/declarative/qml/qmlintegercache.cpp b/src/declarative/qml/qmlintegercache.cpp new file mode 100644 index 0000000..1bc4086 --- /dev/null +++ b/src/declarative/qml/qmlintegercache.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlintegercache_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QmlIntegerCache::QmlIntegerCache(QmlEngine *e) +: engine(e) +{ +} + +QmlIntegerCache::~QmlIntegerCache() +{ + qDeleteAll(stringCache); +} + +void QmlIntegerCache::add(const QString &id, int value) +{ + Q_ASSERT(!stringCache.contains(id)); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### use contextClass + QScriptDeclarativeClass::PersistentIdentifier *d = + enginePriv->objectClass->createPersistentIdentifier(id); + d->value = value; + + stringCache.insert(id, d); + identifierCache.insert(d->identifier, d); +} + +int QmlIntegerCache::value(const QString &id) +{ + Data *d = stringCache.value(id); + return d?d->value:-1; +} + +QmlIntegerCache *QmlIntegerCache::createForEnums(QmlType *type, QmlEngine *engine) +{ + Q_ASSERT(type); + Q_ASSERT(engine); + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + const QMetaObject *mo = type->metaObject(); + + for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum enumerator = mo->enumerator(ii); + + for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + QString name = QLatin1String(enumerator.key(jj)); + int value = enumerator.value(jj); + + if (!name.at(0).isUpper()) + continue; + + if (cache->stringCache.contains(name)) + continue; + + cache->add(name, value); + } + } + + return cache; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlintegercache_p.h b/src/declarative/qml/qmlintegercache_p.h new file mode 100644 index 0000000..fda80c6 --- /dev/null +++ b/src/declarative/qml/qmlintegercache_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINTEGERCACHE_P_H +#define QMLINTEGERCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlType; +class QmlEngine; +class QmlIntegerCache : public QmlRefCount +{ +public: + QmlIntegerCache(QmlEngine *); + virtual ~QmlIntegerCache(); + + inline int count() const; + void add(const QString &, int); + int value(const QString &); + inline int value(const QScriptDeclarativeClass::Identifier &id) const; + + static QmlIntegerCache *createForEnums(QmlType *, QmlEngine *); +private: + struct Data { + int value; + }; + + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QmlEngine *engine; +}; + +int QmlIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const +{ + Data *d = identifierCache.value(id); + return d?d->value:-1; +} + +int QmlIntegerCache::count() const +{ + return stringCache.count(); +} + +QT_END_NAMESPACE + +#endif // QMLINTEGERCACHE_P_H + diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index f7882dc..ec143a7 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -218,7 +218,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (cache) { QmlPropertyCache::Data *data = cache->property(name); - if (data && !data->isFunction) { + if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) { type = QmlMetaProperty::Property; propType = data->propType; coreIdx = data->coreIndex; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp new file mode 100644 index 0000000..0ae1809 --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlobjectscriptclass_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct ObjectData { + ObjectData(QObject *o) : object(o) {} + QGuard object; +}; + +static QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().data().toQObject(); + QString ret = QLatin1String("Qml Object, "); + if(obj){ + //###Should this be designer or developer details? Dev for now. + //TODO: Can we print the id too? + ret += QLatin1String("\""); + ret += obj->objectName(); + ret += QLatin1String("\" "); + ret += QLatin1String(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + ret += QLatin1String(")"); + }else{ + ret += QLatin1String("null"); + } + return engine->newVariant(ret); +} + +static QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + obj->deleteLater(); + //### Should this be delayed as well? + context->thisObject().setData(QScriptValue(engine, 0)); + } + return engine->nullValue(); +} + +/* + The QmlObjectScriptClass handles property access for QObjects + via QtScript. It is also used to provide a more useful API in + QtScript for QML. + */ +QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), lastData(0), + engine(bindEngine) +{ + engine = bindEngine; + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); + + m_destroy = scriptEngine->newFunction(QmlObjectDestroy); + m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); +} + +QmlObjectScriptClass::~QmlObjectScriptClass() +{ + delete m_destroyId; +} + +QScriptValue QmlObjectScriptClass::newQObject(QObject *object) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, (Object)new ObjectData(object)); +} + +QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const +{ + return value.toQObject(); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + return queryProperty(toQObject(object), name, flags); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + lastData = 0; + + if (name == m_destroyId->identifier) + return QScriptClass::HandlesReadAccess; + + if (!obj) + return 0; + + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (ddata) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + QmlPropertyCache::Data *property = cache->property(name); + if (!property) return 0; + + if (flags == QScriptClass::HandlesReadAccess) { + lastData = property; + return QScriptClass::HandlesReadAccess; + } else if (property->propType > 0 && property->propType < QVariant::UserType) { + lastData = property; + return flags; + } + } + + // Fallback + return QmlEnginePrivate::get(engine)->queryObject(toString(name), &m_id, obj); +} + +QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifier &name) +{ + return property(toQObject(object), name); +} + +QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name) +{ + if (name == m_destroyId->identifier) + return m_destroy; + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!obj) { + return QScriptValue(); + } else if (lastData) { + + if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, + lastData->notifyIndex); + } + + if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = *(QObject **)var.constData(); + return newQObject(rv); + } else { + return qScriptValueFromValue(scriptEngine, var); + } + } + + } else { + return QmlEnginePrivate::get(engine)->propertyObject(toString(name), obj, m_id); + } +} + +void QmlObjectScriptClass::setProperty(const Object &object, + const Identifier &name, + const QScriptValue &value) +{ + return setProperty(toQObject(object), name, value); +} + +void QmlObjectScriptClass::setProperty(QObject *obj, + const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(name); + Q_UNUSED(object); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!obj) { + return; + } else if (lastData) { + switch (lastData->propType) { + case 1: + { + bool b = value.toBoolean(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + case 2: + { + int b = value.toInteger(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + case 6: + { + double b = value.toNumber(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + default: + { + QMetaProperty p = obj->metaObject()->property(lastData->coreIndex); + p.write(obj, value.toVariant()); + } + } + } else { + QmlEnginePrivate::get(engine)->setPropertyObject(value, m_id); + } +} + +QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) +{ + if (ok) *ok = true; + + ObjectData *data = (ObjectData*)object; + return data->object.data(); +} + +void QmlObjectScriptClass::destroyed(const Object &object) +{ + ObjectData *data = (ObjectData*)object; + delete data; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h new file mode 100644 index 0000000..c25718c --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLOBJECTSCRIPTCLASS_P_H +#define QMLOBJECTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlObjectScriptClass : public QScriptDeclarativeClass +{ +public: + QmlObjectScriptClass(QmlEngine *); + ~QmlObjectScriptClass(); + + QScriptValue newQObject(QObject *); + QObject *toQObject(const QScriptValue &) const; + + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, + QScriptClass::QueryFlags flags); + QScriptValue property(QObject *, const Identifier &); + void setProperty(QObject *, const Identifier &name, const QScriptValue &); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QObject *toQObject(const Object &, bool *ok = 0); + virtual void destroyed(const Object &); + +private: + uint m_id; + QmlPropertyCache::Data *lastData; + struct Dummy {}; + PersistentIdentifier *m_destroyId; + QScriptValue m_destroy; + QmlEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QMLOBJECTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index f88b3a3..95b819a 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -42,6 +42,8 @@ #include "qmlpropertycache_p.h" #include "qmlengine_p.h" +QT_BEGIN_NAMESPACE + QmlPropertyCache::QmlPropertyCache() { } @@ -78,12 +80,19 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QMetaProperty p = metaObject->property(ii); QString propName = QLatin1String(p.name()); - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass2->createPersistentIdentifier(propName); + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass->createPersistentIdentifier(propName); + data->propType = p.userType(); data->coreIndex = ii; + data->notifyIndex = p.notifySignalIndex(); data->name = propName; + if (p.isConstant()) + data->flags |= Data::IsConstant; + if (QmlMetaType::isObject(data->propType)) + data->flags |= Data::IsQObjectDerived; + cache->indexCache[ii] = data; if (cache->stringCache.contains(propName)) @@ -107,14 +116,14 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject if (cache->stringCache.contains(methodName)) continue; - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass2->createPersistentIdentifier(methodName); + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass->createPersistentIdentifier(methodName); cache->stringCache.insert(methodName, data); cache->identifierCache.insert(data->identifier, data); data->addref(); data->addref(); - data->isFunction = true; + data->flags |= Data::IsFunction; } return cache; @@ -135,3 +144,4 @@ QmlPropertyCache::property(const QString &str) const return stringCache.value(str); } +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index c10fafa..21c8ef3 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -67,33 +67,50 @@ public: QmlPropertyCache(); virtual ~QmlPropertyCache(); - struct Data : public QmlRefCount { - Data() : isFunction(false) {} + struct Data { + inline Data(); - bool isFunction; + enum Flag { IsFunction = 0x00000001, + IsQObjectDerived = 0x00000002, + IsConstant = 0x00000004 }; + Q_DECLARE_FLAGS(Flags, Flag) + + Flags flags; int propType; int coreIndex; + int notifyIndex; QString name; }; static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); - Data *property(const QScriptDeclarativeClass::Identifier &id) const { - return identifierCache.value(id); - } - + inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; Data *property(const QString &) const; Data *property(int) const; private: - typedef QVector *> IndexCache; - typedef QHash *> StringCache; - typedef QHash *> IdentifierCache; + struct RData : public Data, public QmlRefCount {}; + + typedef QVector *> IndexCache; + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; IndexCache indexCache; StringCache stringCache; IdentifierCache identifierCache; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlPropertyCache::Data::Flags); + +QmlPropertyCache::Data::Data() +: flags(0), propType(0), coreIndex(-1), notifyIndex(-1) +{ +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index a5d2732..4ba412b 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -166,8 +166,8 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); - if (instr.init.idSize) - cp->setIdPropertyCount(instr.init.idSize); + if (instr.init.contextCache != -1) + cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); } break; diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index f2716e4..d8b4822 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -71,6 +71,7 @@ #include "bridge/qscriptclassobject_p.h" #include "bridge/qscriptvariant_p.h" #include "bridge/qscriptqobject_p.h" +#include "bridge/qscriptdeclarativeclass_p.h" /*! \since 4.3 @@ -1529,6 +1530,8 @@ QVariant QScriptValue::toVariant() const #endif else if (isArray()) return QScriptEnginePrivate::variantListFromArray(*this); + else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this)) + return dc->toVariant(QScriptDeclarativeClass::object(*this)); // try to convert to primitive JSC::ExecState *exec = d->engine->currentFrame; JSC::JSValue savedException; @@ -1619,6 +1622,8 @@ QObject *QScriptValue::toQObject() const if (isQObject()) { QScriptObject *object = static_cast(JSC::asObject(d->jscValue)); return static_cast(object->delegate())->value(); + } else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this)) { + return dc->toQObject(QScriptDeclarativeClass::object(*this)); } else if (isVariant()) { QVariant var = toVariant(); int type = var.userType(); diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index c753379..c017e13 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -219,3 +220,15 @@ void QScriptDeclarativeClass::destroyed(const Object &object) Q_UNUSED(object); } +QObject *QScriptDeclarativeClass::toQObject(const Object &, bool *ok) +{ + if (ok) *ok = false; + return 0; +} + +QVariant QScriptDeclarativeClass::toVariant(const Object &, bool *ok) +{ + if (ok) *ok = false; + return QVariant(); +} + diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 5705a51..a00a286 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -112,6 +112,8 @@ public: virtual QStringList propertyNames(const Object &); + virtual QObject *toQObject(const Object &, bool *ok = 0); + virtual QVariant toVariant(const Object &, bool *ok = 0); virtual void destroyed(const Object &); static void destroyPersistentIdentifier(void **); -- cgit v0.12