From 8c84f7ca274e5c8e4d249ede904bb247659dbce4 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 8 Jan 2010 19:02:10 +1000 Subject: Optimization: Cache compiled dynamic functions --- src/declarative/qml/qmlcompiler.cpp | 15 ++++++-- src/declarative/qml/qmlcontext.cpp | 2 +- src/declarative/qml/qmlcontext_p.h | 1 - src/declarative/qml/qmlengine.cpp | 5 +-- src/declarative/qml/qmlexpression.cpp | 32 ++++++++++++----- src/declarative/qml/qmlexpression_p.h | 2 ++ src/declarative/qml/qmlvmemetaobject.cpp | 61 ++++++++++++++++++-------------- src/declarative/qml/qmlvmemetaobject_p.h | 10 +++--- 8 files changed, 81 insertions(+), 47 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 7f11a23..7c43305 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2341,13 +2341,24 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) } for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { - const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + Object::DynamicSlot &s = obj->dynamicSlots[ii]; QByteArray sig(s.name + '('); + QString funcScript(QLatin1String("(function(")); + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { - if (jj) sig.append(','); + if (jj) { + sig.append(','); + funcScript.append(QLatin1Char(',')); + } + funcScript.append(s.parameterNames.at(jj)); sig.append("QVariant"); } sig.append(')'); + funcScript.append(QLatin1Char(')')); + funcScript.append(s.body); + funcScript.append(QLatin1Char(')')); + s.body = funcScript; + QMetaMethodBuilder b = builder.addSlot(sig); b.setReturnType("QVariant"); b.setParameterNames(s.parameterNames); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index e063981..e7ac864 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE QmlContextPrivate::QmlContextPrivate() -: parent(0), engine(0), isInternal(false), isTemporary(false), propertyNames(0), +: parent(0), engine(0), isInternal(false), propertyNames(0), notifyIndex(-1), highPriorityCount(0), imports(0), expressions(0), contextObjects(0), idValues(0), idValueCount(0), optimizedBindings(0) { diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index cb89474..e682ee2 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -88,7 +88,6 @@ public: QmlEngine *engine; bool isInternal; - bool isTemporary; QmlIntegerCache *propertyNames; QList propertyValues; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 708cdd1..19a20e8 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -649,10 +649,7 @@ QmlContext *QmlEnginePrivate::getContext(QScriptContext *ctxt) QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); Q_ASSERT(scopeNode.isValid()); Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass); - QmlContext *context = contextClass->contextFromValue(scopeNode); - while (context && QmlContextPrivate::get(context)->isTemporary) - context = context->parentContext(); - return context; + return contextClass->contextFromValue(scopeNode); } QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 1321601..1587d61 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -138,19 +138,13 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, dd->cachedPrograms[progIdx] = new QScriptProgram(data->expression, data->url, data->line); } -#endif - - QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); - scriptContext->pushScope(ep->contextClass->newContext(ctxt, me)); -#if !defined(Q_OS_SYMBIAN) - data->expressionFunction = scriptEngine->evaluate(*dd->cachedPrograms.at(progIdx)); + data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx)); #else - data->expressionFunction = scriptEngine->evaluate(data->expression); + data->expressionFunction = evalInObjectScope(ctxt, me, data->expression); #endif data->expressionFunctionValid = true; - scriptEngine->popContext(); } } @@ -158,6 +152,28 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, data->me = me; } +QScriptValue QmlExpressionPrivate::evalInObjectScope(QmlContext *context, QObject *object, + const QString &program) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(context->engine()); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); + scriptContext->pushScope(ep->contextClass->newContext(context, object)); + QScriptValue rv = ep->scriptEngine.evaluate(program); + ep->scriptEngine.popContext(); + return rv; +} + +QScriptValue QmlExpressionPrivate::evalInObjectScope(QmlContext *context, QObject *object, + const QScriptProgram &program) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(context->engine()); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); + scriptContext->pushScope(ep->contextClass->newContext(context, object)); + QScriptValue rv = ep->scriptEngine.evaluate(program); + ep->scriptEngine.popContext(); + return rv; +} + /*! \class QmlExpression \brief The QmlExpression class evaluates ECMAScript in a QML context. diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 3f87b2f..8561a57 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -164,6 +164,8 @@ public: } static void exceptionToError(QScriptEngine *, QmlError &); + static QScriptValue evalInObjectScope(QmlContext *, QObject *, const QString &); + static QScriptValue evalInObjectScope(QmlContext *, QObject *, const QScriptProgram &); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index 3b1f068..fd699c3 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -44,6 +44,7 @@ #include "qml.h" #include "qmlrefcount_p.h" #include "qmlexpression.h" +#include "qmlexpression_p.h" #include "qmlcontext_p.h" #include @@ -56,11 +57,11 @@ QT_BEGIN_NAMESPACE QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QmlVMEMetaData *meta, - QmlRefCount *rc) -: object(obj), ref(rc), ctxt(qmlContext(obj)), metaData(meta), parent(0) + QmlCompiledData *cdata) +: object(obj), compiledData(cdata), ctxt(qmlContext(obj)), metaData(meta), methods(0), + parent(0) { - if (ref) - ref->addref(); + compiledData->addref(); *static_cast(this) = *other; this->d.superdata = obj->metaObject(); @@ -91,12 +92,11 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, QmlVMEMetaObject::~QmlVMEMetaObject() { - if (ref) - ref->release(); - if (parent) - delete parent; + compiledData->release(); + delete parent; qDeleteAll(listProperties); delete [] data; + delete [] methods; } int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) @@ -260,29 +260,36 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) id -= plainSignals; if (id < metaData->methodCount) { + if (!ctxt->engine()) + return -1; // We can't run the method + + QmlEnginePrivate *ep = QmlEnginePrivate::get(ctxt->engine()); + + if (!methods) + methods = new QScriptValue[metaData->methodCount]; + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; - const QChar *body = - (const QChar *)(((const char*)metaData) + data->bodyOffset); + if (!methods[id].isValid()) { + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); - QString code = QString::fromRawData(body, data->bodyLength); + QString code = QString::fromRawData(body, data->bodyLength); - QVariant rv; - if (0 == (metaData->methodData() + id)->parameterCount) { - QmlExpression expr(ctxt, code, object); - expr.setTrackChange(false); - rv = expr.value(); - } else { - QmlContext newCtxt(ctxt); - QmlContextPrivate::get(&newCtxt)->isTemporary = true; - QMetaMethod m = method(_id); - QList names = m.parameterNames(); - for (int ii = 0; ii < names.count(); ++ii) - newCtxt.setContextProperty(QString::fromLatin1(names.at(ii)), *(QVariant *)a[ii + 1]); - QmlExpression expr(&newCtxt, code, object); - expr.setTrackChange(false); - rv = expr.value(); + // XXX Use QScriptProgram + methods[id] = QmlExpressionPrivate::evalInObjectScope(ctxt, object, code); } - if (a[0]) *reinterpret_cast(a[0]) = rv; + + QScriptValueList args; + if (data->parameterCount) { + for (int ii = 0; ii < data->parameterCount; ++ii) { + args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]); + } + } + QScriptValue rv = methods[id].call(ep->scriptEngine.globalObject(), args); + + if (a[0]) *reinterpret_cast(a[0]) = ep->scriptValueToVariant(rv); + + return -1; } return -1; } diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 462f652..b79e42c 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -62,6 +62,7 @@ #include #include "qmlguard_p.h" +#include "qmlcompiler_p.h" QT_BEGIN_NAMESPACE @@ -88,7 +89,7 @@ struct QmlVMEMetaData int parameterCount; int bodyOffset; int bodyLength; - int _dummy; + int scriptProgram; }; PropertyData *propertyData() const { @@ -108,8 +109,8 @@ class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, const QmlVMEMetaData *data, - QmlRefCount * = 0); + QmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QmlVMEMetaData *data, + QmlCompiledData *compiledData); ~QmlVMEMetaObject(); void registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor); @@ -119,7 +120,7 @@ protected: private: QObject *object; - QmlRefCount *ref; + QmlCompiledData *compiledData; QmlGuard ctxt; const QmlVMEMetaData *metaData; @@ -130,6 +131,7 @@ private: QBitArray aConnected; QBitArray aInterceptors; QHash > interceptors; + QScriptValue *methods; QAbstractDynamicMetaObject *parent; -- cgit v0.12