diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-10-24 14:51:02 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-31 10:50:38 +0100 |
commit | 34c85bb56c92316a6ce1c79d25f9653fec14791c (patch) | |
tree | 6d3d43de33fa53a1353c52506e989ae126f1361b /src/qml/compiler/qqmlcodegenerator.cpp | |
parent | bb7d26ebb0c2e7a9f06a030be8bfcd00e346e06f (diff) |
Initial support for resolving meta-property access for the scope and context objects at QML compile time
This avoids having to do a string lookup for ids and in the import cache at
run-time, before we can do a string hash lookup in the property cache. Instead
we resolve final properties in the context and scope object at compile time and
look them up at run-time using their index instead. The dependencies to these
properties are also tracked separately and recorded in the compiled data.
This is merely the initial patch. There's a lot left to do, such as having
specialized getter and setters for specific property types. Setters are missing
altogether right now and will fall back to name lookup.
Change-Id: If3cb4e7c9454ef4850a615f0935b311c9395b165
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler/qqmlcodegenerator.cpp')
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 84 |
1 files changed, 76 insertions, 8 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index fc485e82f2..7b1984fce0 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -1198,22 +1198,31 @@ int QmlUnitGenerator::getStringId(const QString &str) const return jsUnitGenerator->getStringId(str); } -JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot) +JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports) : QQmlJS::Codegen(/*strict mode*/false) , sourceCode(sourceCode) , jsEngine(jsEngine) , qmlRoot(qmlRoot) + , imports(imports) { _module = jsModule; _module->setFileName(fileName); } -QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(AST::Node *contextRoot, - const QList<AST::Node*> &functions, - const ObjectIdMapping &objectIds) +void JSCodeGen::beginContextScope(const JSCodeGen::ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject) { - this->idObjects = objectIds; + _idObjects = objectIds; + _contextObject = contextObject; + _scopeObject = 0; +} +void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject) +{ + _scopeObject = scopeObject; +} + +QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions) +{ QVector<int> runtimeFunctionIndices(functions.size()); ScanFunctions scan(this, sourceCode, GlobalCode); @@ -1274,18 +1283,77 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(AST::Node *context return runtimeFunctionIndices; } -V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col) const +static QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup) +{ + *propertyExistsButForceNameLookup = false; + QQmlPropertyData *pd = cache->property(name, /*object*/0, /*context*/0); + + // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time + if (pd && pd->isFunction()) { + *propertyExistsButForceNameLookup = true; + pd = 0; + } + + if (pd && !cache->isAllowedInRevision(pd)) + pd = 0; + + return pd; +} + +V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col) { V4IR::Expr *result = 0; // Implement QML lookup semantics in the current file context. + // + // Note: We do not check if properties of the qml scope object or context object + // are final. That's because QML tries to get as close as possible to lexical scoping, + // which means in terms of properties that only those visible at compile time are chosen. + // I.e. access to a "foo" property declared within the same QML component as "property int foo" + // will always access that instance and as integer. If a sub-type implements its own property string foo, + // then that one is not chosen for accesses from within this file, because it wasn't visible at compile + // time. This corresponds to the logic in QQmlPropertyCache::findProperty to find the property associated + // with the correct QML context. // Look for IDs first. - foreach (const IdMapping &mapping, idObjects) + foreach (const IdMapping &mapping, _idObjects) if (name == mapping.name) { - result = _block->QML_CONTEXT_ID_MEMBER(mapping.name, mapping.idIndex, line, col); + result = _block->QML_CONTEXT_ID_MEMBER(_block->NAME(V4IR::Name::builtin_qml_id_scope, line, col), + _function->newString(mapping.name), mapping.idIndex); break; } + if (!result) { + QQmlTypeNameCache::Result r = imports->query(name); + if (r.isValid()) + return 0; // TODO: We can't do fast lookup for these yet. + } + + if (!result && _scopeObject) { + bool propertyExistsButForceNameLookup = false; + QQmlPropertyData *pd = lookupQmlCompliantProperty(_scopeObject, name, &propertyExistsButForceNameLookup); + if (propertyExistsButForceNameLookup) + return 0; + if (pd) { + int base = _block->newTemp(); + move(_block->TEMP(base), _block->NAME(V4IR::Name::builtin_qml_scope_object, line, col)); + result = _block->QML_QOBJECT_PROPERTY(_block->TEMP(base), + _function->newString(name), pd); + } + } + + if (!result && _contextObject) { + bool propertyExistsButForceNameLookup = false; + QQmlPropertyData *pd = lookupQmlCompliantProperty(_contextObject, name, &propertyExistsButForceNameLookup); + if (propertyExistsButForceNameLookup) + return 0; + if (pd) { + int base = _block->newTemp(); + move(_block->TEMP(base), _block->NAME(V4IR::Name::builtin_qml_context_object, line, col)); + result = _block->QML_QOBJECT_PROPERTY(_block->TEMP(base), + _function->newString(name), pd); + } + } + if (result) { _function->hasQmlDependencies = true; return result; |