summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2010-06-23 15:22:47 (GMT)
committerKent Hansen <kent.hansen@nokia.com>2010-06-25 06:59:13 (GMT)
commita91f8d704c3ff3826f0ea8b7e73fc6d91dd5b836 (patch)
tree26c0bb1921eb8b3fc73b01be94dc1823d7322e19 /src/declarative
parentf793344d17b0ec5df4987e123cc1e3b008a949bb (diff)
downloadQt-a91f8d704c3ff3826f0ea8b7e73fc6d91dd5b836.zip
Qt-a91f8d704c3ff3826f0ea8b7e73fc6d91dd5b836.tar.gz
Qt-a91f8d704c3ff3826f0ea8b7e73fc6d91dd5b836.tar.bz2
Use custom static scopes to improve QML/JavaScript performance
This commit introduces a new internal JS object type, QScriptStaticScopeObject, that enables the JS compiler to make more aggressive optimizations of scoped property access. QScriptStaticScopeObject registers all its properties in a symbol table that the JS compiler has access to. If the compiler finds the property in the symbol table, it will generate the fast index-based op_{get,put}_scoped_var bytecodes, rather than the dynamic (slow) op_resolve and friends. If the compiler _doesn't_ find the property in the symbol table, it infers that it's safe to skip the scope object when later resolving the property, which will also improve performance (see op_resolve_skip bytecode). QScriptStaticScopeObject is only safe to use when all relevant properties are known at JS compile time; that is, when a function that has the static scope object in its scope chain is compiled. It's up to the user of the class (e.g. QtDeclarative) to ensure that this constraint is not violated. The API for constructing QScriptStaticScopeObject instances is not public; it lives in QScriptDeclarativeClass for now, an internal class exported for the purpose of QML. The instance is returned as a QScriptValue and can be manipulated like any other JS object (e.g. by QScriptValue::setProperty()). The other part of this commit utilizes QScriptStaticScopeObject in QtDeclarative in the two major places where it's currently possible: 1) QML disallows adding properties to the Global Object. Furthermore, it's not possible for QML IDs and properties to "shadow" global variables. Hence, a QScriptStaticScopeObject can be used to hold all the standard ECMA properties, and this scope object can come _before_ the QML component in the scope chain. This enables binding expressions and scripts to have optimized (direct) access to e.g. Math.sin. 2) Imported scripts can have their properties (resulting from variable declarations ("var" statements) and function declarations) added to a static scope object. This enables functions in the script to have optimized (direct) access to the script's own properties, as well as to global properties such as Math. With this change, it's no longer possible to delete properties of the Global Object, nor delete properties of an imported script. It's a compromise we make in order to make the optimization safe. Task-number: QTBUG-8576 Reviewed-by: Aaron Kennedy Reviewed-by: Olivier Goffart Reviewed-by: Jedrzej Nowacki
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp12
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp8
-rw-r--r--src/declarative/qml/qdeclarativeglobalscriptclass.cpp39
-rw-r--r--src/declarative/qml/qdeclarativeglobalscriptclass_p.h4
-rw-r--r--src/declarative/qml/qdeclarativeinclude.cpp2
5 files changed, 37 insertions, 28 deletions
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index 2221d78..60e9dd3 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -660,10 +660,9 @@ void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url));
- scriptContext->pushScope(enginePriv->globalClass->globalObject());
+ scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
- QScriptValue scope = scriptEngine->newObject();
- scriptContext->setActivationObject(scope);
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
scriptContext->pushScope(scope);
scriptEngine->evaluate(code, url, 1);
@@ -686,10 +685,9 @@ void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url));
- scriptContext->pushScope(enginePriv->globalClass->globalObject());
-
- QScriptValue scope = scriptEngine->newObject();
- scriptContext->setActivationObject(scope);
+ scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
+
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
scriptContext->pushScope(scope);
scriptEngine->evaluate(code, url, 1);
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index b1aecfa..8ae5f2f 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -145,7 +145,7 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *ex
if (!dd->cachedClosures.at(progIdx)) {
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
scriptContext->pushScope(ep->contextClass->newSharedContext());
- scriptContext->pushScope(ep->globalClass->globalObject());
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line));
scriptEngine->popContext();
}
@@ -188,7 +188,7 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
} else {
scriptContext->pushScope(ep->contextClass->newContext(context, object));
}
- scriptContext->pushScope(ep->globalClass->globalObject());
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
ep->scriptEngine.popContext();
return rv;
@@ -206,7 +206,7 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
} else {
scriptContext->pushScope(ep->contextClass->newContext(context, object));
}
- scriptContext->pushScope(ep->globalClass->globalObject());
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
QScriptValue rv = ep->scriptEngine.evaluate(program);
ep->scriptEngine.popContext();
return rv;
@@ -369,7 +369,7 @@ QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool *
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
data->expressionContext = ep->contextClass->newContext(data->context(), data->me);
scriptContext->pushScope(data->expressionContext);
- scriptContext->pushScope(ep->globalClass->globalObject());
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
if (data->expressionRewritten) {
data->expressionFunction = scriptEngine->evaluate(data->expression,
diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass.cpp b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
index 6e107fb..39ea101 100644
--- a/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
+++ b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
@@ -41,10 +41,13 @@
#include "private/qdeclarativeglobalscriptclass_p.h"
+#include <QtCore/qvector.h>
#include <QtScript/qscriptstring.h>
#include <QtScript/qscriptengine.h>
#include <QtScript/qscriptvalueiterator.h>
+#include <private/qscriptdeclarativeclass_p.h>
+
QT_BEGIN_NAMESPACE
/*
@@ -55,23 +58,31 @@ QDeclarativeGlobalScriptClass::QDeclarativeGlobalScriptClass(QScriptEngine *engi
{
QString eval = QLatin1String("eval");
- QScriptValue globalObject = engine->globalObject();
+ QScriptValue originalGlobalObject = engine->globalObject();
- m_globalObject = engine->newObject();
QScriptValue newGlobalObject = engine->newObject();
- QScriptValueIterator iter(globalObject);
-
- while (iter.hasNext()) {
- iter.next();
-
- QString name = iter.name();
-
- if (name != eval)
- m_globalObject.setProperty(iter.scriptName(), iter.value());
- newGlobalObject.setProperty(iter.scriptName(), iter.value());
-
- m_illegalNames.insert(name);
+ {
+ QScriptValueIterator iter(originalGlobalObject);
+ QVector<QString> names;
+ QVector<QScriptValue> values;
+ QVector<QScriptValue::PropertyFlags> flags;
+ while (iter.hasNext()) {
+ iter.next();
+
+ QString name = iter.name();
+
+ if (name != eval) {
+ names.append(name);
+ values.append(iter.value());
+ flags.append(iter.flags() | QScriptValue::Undeletable);
+ }
+ newGlobalObject.setProperty(iter.scriptName(), iter.value());
+
+ m_illegalNames.insert(name);
+ }
+ m_staticGlobalObject = QScriptDeclarativeClass::newStaticScopeObject(
+ engine, names.size(), names.constData(), values.constData(), flags.constData());
}
newGlobalObject.setScriptClass(this);
diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass_p.h b/src/declarative/qml/qdeclarativeglobalscriptclass_p.h
index 7690edd..414bf02 100644
--- a/src/declarative/qml/qdeclarativeglobalscriptclass_p.h
+++ b/src/declarative/qml/qdeclarativeglobalscriptclass_p.h
@@ -75,13 +75,13 @@ public:
void explicitSetProperty(const QString &, const QScriptValue &);
- const QScriptValue &globalObject() const { return m_globalObject; }
+ const QScriptValue &staticGlobalObject() const { return m_staticGlobalObject; }
const QSet<QString> &illegalNames() const { return m_illegalNames; }
private:
QSet<QString> m_illegalNames;
- QScriptValue m_globalObject;
+ QScriptValue m_staticGlobalObject;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeinclude.cpp b/src/declarative/qml/qdeclarativeinclude.cpp
index c29005a..f26b54f 100644
--- a/src/declarative/qml/qdeclarativeinclude.cpp
+++ b/src/declarative/qml/qdeclarativeinclude.cpp
@@ -240,7 +240,7 @@ QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *e
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
scriptContext->pushScope(ep->contextClass->newUrlContext(context, 0, urlString));
- scriptContext->pushScope(ep->globalClass->globalObject());
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
scriptContext->pushScope(scope);
scriptContext->setActivationObject(scope);