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 | |
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')
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 84 | ||||
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator_p.h | 16 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 14 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 95 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler_p.h | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 26 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 15 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 25 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 48 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 49 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 19 |
17 files changed, 373 insertions, 62 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; diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 1b72e96097..43bc979205 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE +class QQmlTypeNameCache; + namespace QtQml { using namespace QQmlJS; @@ -346,7 +348,7 @@ private: struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen { JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, - QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot); + QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports); struct IdMapping { @@ -355,18 +357,24 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen }; typedef QVector<IdMapping> ObjectIdMapping; + void beginContextScope(const ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject); + void beginObjectScope(QQmlPropertyCache *scopeObject); + // Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions - QVector<int> generateJSCodeForFunctionsAndBindings(AST::Node *contextRoot, const QList<AST::Node*> &functions, const ObjectIdMapping &objectIds = ObjectIdMapping()); + QVector<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions); protected: - virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col) const; + virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col); private: QString sourceCode; QQmlJS::Engine *jsEngine; // needed for memory pool AST::UiProgram *qmlRoot; + QQmlTypeNameCache *imports; - ObjectIdMapping idObjects; + ObjectIdMapping _idObjects; + QQmlPropertyCache *_contextObject; + QQmlPropertyCache *_scopeObject; }; } // namespace QtQml diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index cb15c2c885..0be8791d73 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1424,7 +1424,7 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col) Environment *e = _env; V4IR::Function *f = _function; - while (f && e->parent && e->compilationMode != QmlBinding) { + while (f && e->parent) { if (f->insideWithOrCatch || (f->isNamedExpression && f->name == name)) return _block->NAME(name, line, col); @@ -1460,7 +1460,7 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col) } -V4IR::Expr *Codegen::fallbackNameLookup(const QString &name, int line, int col) const +V4IR::Expr *Codegen::fallbackNameLookup(const QString &name, int line, int col) { Q_UNUSED(name) Q_UNUSED(line) @@ -1955,7 +1955,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, _env->enter("arguments", Environment::VariableDeclaration); // variables in global code are properties of the global context object, not locals as with other functions. - if (_env->compilationMode == FunctionCode) { + if (_env->compilationMode == FunctionCode || _env->compilationMode == QmlBinding) { unsigned t = 0; for (Environment::MemberMap::iterator it = _env->members.begin(); it != _env->members.end(); ++it) { const QString &local = it.key(); @@ -2012,7 +2012,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, if (member.function) { const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals, member.function->body ? member.function->body->elements : 0); - if (! _env->parent || _env->compilationMode == QmlBinding) { + if (! _env->parent) { move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn), _block->CLOSURE(function)); } else { diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 369df712c5..f5cdd27efa 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -72,7 +72,10 @@ public: GlobalCode, EvalCode, FunctionCode, - QmlBinding + QmlBinding // This is almost the same as EvalCode, except: + // * function declarations are moved to the return address when encountered + // * return statements are allowed everywhere (like in FunctionCode) + // * variable declarations are treated as true locals (like in FunctionCode) }; void generateFromProgram(const QString &fileName, @@ -324,7 +327,7 @@ protected: V4IR::Expr *identifier(const QString &name, int line = 0, int col = 0); // Hook provided to implement QML lookup semantics - virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col) const; + virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col); // nodes virtual bool visit(AST::ArgumentList *ast); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 60a697e53e..1c0d72e521 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -235,7 +235,11 @@ struct Function // Qml Extensions Begin quint32 nDependingIdObjects; - quint32 dependingIdObjectsOffset; + quint32 dependingIdObjectsOffset; // Array of resolved ID objects + quint32 nDependingContextProperties; + quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index) + quint32 nDependingScopeProperties; + quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index) // Qml Extensions End // quint32 formalsIndex[nFormals] @@ -247,11 +251,13 @@ struct Function const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); } const quint32 *lineNumberMapping() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + lineNumberMappingOffset); } const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); } + const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); } + const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); } - inline bool hasQmlDependencies() const { return nDependingIdObjects; } + inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; } - static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings, int nIdObjectDependencies) { - return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings + nIdObjectDependencies) * sizeof(quint32) + 7) & ~0x7; + static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings, int nIdObjectDependencies, int nPropertyDependencies) { + return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings + nIdObjectDependencies + 2 * nPropertyDependencies) * sizeof(quint32) + 7) & ~0x7; } }; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 0b3e85352e..4ee34d8aec 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -43,6 +43,7 @@ #include <qv4compileddata_p.h> #include <qv4isel_p.h> #include <qv4engine_p.h> +#include <private/qqmlpropertycache_p.h> QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::V4IR::Module *module, int headerSize) : irModule(module) @@ -172,9 +173,19 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total if (f->hasQmlDependencies) { QQmlJS::V4IR::QmlDependenciesCollector depCollector; - QSet<int> idObjectDeps = depCollector.run(f); + + QSet<int> idObjectDeps; + QSet<QQmlPropertyData*> contextPropertyDeps; + QSet<QQmlPropertyData*> scopePropertyDeps; + + depCollector.run(f, &idObjectDeps, &contextPropertyDeps, &scopePropertyDeps); + if (!idObjectDeps.isEmpty()) qmlIdObjectDependenciesPerFunction.insert(f, idObjectDeps); + if (!contextPropertyDeps.isEmpty()) + qmlContextPropertyDependenciesPerFunction.insert(f, contextPropertyDeps); + if (!scopePropertyDeps.isEmpty()) + qmlScopePropertyDependenciesPerFunction.insert(f, scopePropertyDeps); } } @@ -192,9 +203,24 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd()) lineNumberMappingCount = lineNumberMapping->count() / 2; - const int qmlIdDepsCount = f->hasQmlDependencies ? qmlIdObjectDependenciesPerFunction.value(f).count() : 0; + int qmlIdDepsCount = 0; + int qmlPropertyDepsCount = 0; + + if (f->hasQmlDependencies) { + IdDependencyHash::ConstIterator idIt = qmlIdObjectDependenciesPerFunction.find(f); + if (idIt != qmlIdObjectDependenciesPerFunction.constEnd()) + qmlIdDepsCount += idIt->count(); + + PropertyDependencyHash::ConstIterator it = qmlContextPropertyDependenciesPerFunction.find(f); + if (it != qmlContextPropertyDependenciesPerFunction.constEnd()) + qmlPropertyDepsCount += it->count(); - functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount, qmlIdDepsCount); + it = qmlScopePropertyDependenciesPerFunction.find(f); + if (it != qmlScopePropertyDependenciesPerFunction.constEnd()) + qmlPropertyDepsCount += it->count(); + } + + functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount, qmlIdDepsCount, qmlPropertyDepsCount); } const int totalSize = unitSize + functionDataSize + stringDataSize + jsClassDataSize; @@ -292,7 +318,7 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4 { QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f; - QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(irFunction); + quint32 currentOffset = sizeof(QV4::CompiledData::Function); function->index = index; function->nameIndex = getStringId(*irFunction->name); @@ -306,25 +332,55 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4 if (irFunction->isNamedExpression) function->flags |= CompiledData::Function::IsNamedExpression; function->nFormals = irFunction->formals.size(); - function->formalsOffset = sizeof(QV4::CompiledData::Function); + function->formalsOffset = currentOffset; + currentOffset += function->nFormals * sizeof(quint32); + function->nLocals = irFunction->locals.size(); - function->localsOffset = function->formalsOffset + function->nFormals * sizeof(quint32); + function->localsOffset = currentOffset; + currentOffset += function->nLocals * sizeof(quint32); function->nLineNumberMappingEntries = 0; + QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(irFunction); if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd()) { function->nLineNumberMappingEntries = lineNumberMapping->count() / 2; } - function->lineNumberMappingOffset = function->localsOffset + function->nLocals * sizeof(quint32); + function->lineNumberMappingOffset = currentOffset; + currentOffset += function->nLineNumberMappingEntries * 2 * sizeof(quint32); function->nInnerFunctions = irFunction->nestedFunctions.size(); - function->innerFunctionsOffset = function->lineNumberMappingOffset + function->nLineNumberMappingEntries * 2 * sizeof(quint32); + function->innerFunctionsOffset = currentOffset; + currentOffset += function->nInnerFunctions * sizeof(quint32); function->nDependingIdObjects = 0; + function->nDependingContextProperties = 0; + function->nDependingScopeProperties = 0; + QSet<int> qmlIdObjectDeps; + QSet<QQmlPropertyData*> qmlContextPropertyDeps; + QSet<QQmlPropertyData*> qmlScopePropertyDeps; + if (irFunction->hasQmlDependencies) { qmlIdObjectDeps = qmlIdObjectDependenciesPerFunction.value(irFunction); - function->nDependingIdObjects = qmlIdObjectDeps.count(); - function->dependingIdObjectsOffset = function->innerFunctionsOffset + function->nInnerFunctions * sizeof(quint32); + qmlContextPropertyDeps = qmlContextPropertyDependenciesPerFunction.value(irFunction); + qmlScopePropertyDeps = qmlScopePropertyDependenciesPerFunction.value(irFunction); + + if (!qmlIdObjectDeps.isEmpty()) { + function->nDependingIdObjects = qmlIdObjectDeps.count(); + function->dependingIdObjectsOffset = currentOffset; + currentOffset += function->nDependingIdObjects * sizeof(quint32); + } + + if (!qmlContextPropertyDeps.isEmpty()) { + function->nDependingContextProperties = qmlContextPropertyDeps.count(); + function->dependingContextPropertiesOffset = currentOffset; + currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2; + } + + if (!qmlScopePropertyDeps.isEmpty()) { + function->nDependingScopeProperties = qmlScopePropertyDeps.count(); + function->dependingScopePropertiesOffset = currentOffset; + currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2; + } } function->location.line = irFunction->line; @@ -352,11 +408,24 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4 innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i)); // write QML dependencies - quint32 *writtenIdDeps = (quint32 *)(f + function->dependingIdObjectsOffset); + quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset); foreach (int id, qmlIdObjectDeps) - *writtenIdDeps++ = id; + *writtenDeps++ = id; + + writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset); + foreach (QQmlPropertyData *property, qmlContextPropertyDeps) { + *writtenDeps++ = property->coreIndex; + *writtenDeps++ = property->notifyIndex; + } + + writtenDeps = (quint32 *)(f + function->dependingScopePropertiesOffset); + foreach (QQmlPropertyData *property, qmlScopePropertyDeps) { + *writtenDeps++ = property->coreIndex; + *writtenDeps++ = property->notifyIndex; + } - return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries, function->nDependingIdObjects); + return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries, + function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties); } diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 40b3fe25c0..6338babb5a 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -46,6 +46,8 @@ QT_BEGIN_NAMESPACE +class QQmlPropertyData; + namespace QV4 { namespace CompiledData { @@ -92,7 +94,13 @@ struct Q_QML_EXPORT JSUnitGenerator { QList<QList<CompiledData::JSClassMember> > jsClasses; uint jsClassDataSize; uint headerSize; - QHash<QQmlJS::V4IR::Function *, QSet<int> > qmlIdObjectDependenciesPerFunction; + + typedef QHash<QQmlJS::V4IR::Function *, QSet<int> > IdDependencyHash; + IdDependencyHash qmlIdObjectDependenciesPerFunction; + + typedef QHash<QQmlJS::V4IR::Function *, QSet<QQmlPropertyData*> > PropertyDependencyHash; + PropertyDependencyHash qmlContextPropertyDependenciesPerFunction; + PropertyDependencyHash qmlScopePropertyDependenciesPerFunction; }; } diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 6734d93ae0..d1619962f5 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE F(GetLookup, getLookup) \ F(StoreProperty, storeProperty) \ F(SetLookup, setLookup) \ + F(LoadQObjectProperty, loadQObjectProperty) \ F(Push, push) \ F(CallValue, callValue) \ F(CallProperty, callProperty) \ @@ -122,7 +123,9 @@ QT_BEGIN_NAMESPACE F(MulNumberParams, mulNumberParams) \ F(SubNumberParams, subNumberParams) \ F(LoadThis, loadThis) \ - F(LoadIdObject, loadIdObject) + F(LoadQmlIdObject, loadQmlIdObject) \ + F(LoadQmlContextObject, loadQmlContextObject) \ + F(LoadQmlScopeObject, loadQmlScopeObject) #if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200) # define MOTH_THREADED_INTERPRETER @@ -275,6 +278,12 @@ union Instr Param base; Param result; }; + struct instr_loadQObjectProperty { + MOTH_INSTR_HEADER + int propertyIndex; + Param base; + Param result; + }; struct instr_storeProperty { MOTH_INSTR_HEADER int name; @@ -623,11 +632,19 @@ union Instr MOTH_INSTR_HEADER Param result; }; - struct instr_loadIdObject { + struct instr_loadQmlIdObject { MOTH_INSTR_HEADER Param result; int id; }; + struct instr_loadQmlContextObject { + MOTH_INSTR_HEADER + Param result; + }; + struct instr_loadQmlScopeObject { + MOTH_INSTR_HEADER + Param result; + }; instr_common common; instr_ret ret; @@ -643,6 +660,7 @@ union Instr instr_storeElement storeElement; instr_loadProperty loadProperty; instr_getLookup getLookup; + instr_loadQObjectProperty loadQObjectProperty; instr_storeProperty storeProperty; instr_setLookup setLookup; instr_push push; @@ -702,7 +720,9 @@ union Instr instr_mulNumberParams mulNumberParams; instr_subNumberParams subNumberParams; instr_loadThis loadThis; - instr_loadIdObject loadIdObject; + instr_loadQmlIdObject loadQmlIdObject; + instr_loadQmlContextObject loadQmlContextObject; + instr_loadQmlScopeObject loadQmlScopeObject; static int size(Type type); }; diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 1f00af3972..a012273c12 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -953,6 +953,16 @@ void InstructionSelection::loadIdObject(int id, V4IR::Temp *temp) generateFunctionCall(temp, __qmljs_get_id_object, Assembler::ContextRegister, Assembler::TrustedImm32(id)); } +void InstructionSelection::loadQmlContextObject(V4IR::Temp *temp) +{ + generateFunctionCall(temp, __qmljs_get_context_object, Assembler::ContextRegister); +} + +void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp) +{ + generateFunctionCall(temp, __qmljs_get_scope_object, Assembler::ContextRegister); +} + void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) { if (targetTemp->kind == V4IR::Temp::PhysicalRegister) { @@ -1031,6 +1041,11 @@ void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4 } } +void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target) +{ + generateFunctionCall(target, __qmljs_get_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex)); +} + void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) { diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index 8178866656..46144f22d1 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1470,6 +1470,8 @@ protected: virtual void convertType(V4IR::Temp *source, V4IR::Temp *target); virtual void loadThisObject(V4IR::Temp *temp); virtual void loadIdObject(int id, V4IR::Temp *temp); + virtual void loadQmlContextObject(V4IR::Temp *temp); + virtual void loadQmlScopeObject(V4IR::Temp *temp); virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp); virtual void loadString(const QString &str, V4IR::Temp *targetTemp); virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp); @@ -1478,6 +1480,7 @@ protected: virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target); virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target); virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName); + virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target); virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target); virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex); virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index a2e702dac4..ca0977e057 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -456,12 +456,26 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp) void InstructionSelection::loadIdObject(int id, V4IR::Temp *temp) { - Instruction::LoadIdObject load; + Instruction::LoadQmlIdObject load; load.result = getResultParam(temp); load.id = id; addInstruction(load); } +void InstructionSelection::loadQmlContextObject(V4IR::Temp *temp) +{ + Instruction::LoadQmlContextObject load; + load.result = getResultParam(temp); + addInstruction(load); +} + +void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp) +{ + Instruction::LoadQmlScopeObject load; + load.result = getResultParam(temp); + addInstruction(load); +} + void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) { assert(sourceConst); @@ -555,6 +569,15 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas addInstruction(store); } +void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target) +{ + Instruction::LoadQObjectProperty load; + load.base = getParam(base); + load.propertyIndex = propertyIndex; + load.result = getResultParam(target); + addInstruction(load); +} + void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) { Instruction::LoadElement load; diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index df5c71ce8c..0b44bf35ca 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -115,6 +115,8 @@ protected: virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); virtual void loadThisObject(V4IR::Temp *temp); virtual void loadIdObject(int id, V4IR::Temp *temp); + virtual void loadQmlContextObject(V4IR::Temp *temp); + virtual void loadQmlScopeObject(V4IR::Temp *temp); virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp); virtual void loadString(const QString &str, V4IR::Temp *targetTemp); virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp); @@ -123,6 +125,7 @@ protected: virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target); virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target); virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName); + virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target); virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target); virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex); virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index b9341163de..1a56ddabf1 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -46,6 +46,7 @@ #include "qv4isel_util_p.h" #include "qv4functionobject_p.h" #include "qv4function_p.h" +#include <private/qqmlpropertycache_p.h> #include <QString> @@ -100,8 +101,12 @@ void IRDecoder::visitMove(V4IR::Move *s) } } else if (V4IR::Temp *t = s->target->asTemp()) { if (V4IR::Name *n = s->source->asName()) { - if (*n->id == QStringLiteral("this")) // TODO: `this' should be a builtin. + if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin. loadThisObject(t); + else if (n->builtin == V4IR::Name::builtin_qml_context_object) + loadQmlContextObject(t); + else if (n->builtin == V4IR::Name::builtin_qml_scope_object) + loadQmlScopeObject(t); else getActivationProperty(n, t); return; @@ -138,6 +143,9 @@ void IRDecoder::visitMove(V4IR::Move *s) if (m->type == V4IR::Member::MemberByObjectId) { loadIdObject(m->objectId, t); return; + } else if (m->type == V4IR::Member::MemberOfQObject) { + getQObjectProperty(m->base, m->property->coreIndex, t); + return; } else if (m->base->asTemp() || m->base->asConst()) { getProperty(m->base, *m->name, t); return; diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 6e607d901c..5b9dbafb50 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -141,6 +141,8 @@ public: // to implement by subclasses: virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void loadThisObject(V4IR::Temp *temp) = 0; virtual void loadIdObject(int id, V4IR::Temp *temp) = 0; + virtual void loadQmlContextObject(V4IR::Temp *temp) = 0; + virtual void loadQmlScopeObject(V4IR::Temp *temp) = 0; virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) = 0; virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0; virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0; @@ -148,6 +150,7 @@ public: // to implement by subclasses: virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName) = 0; virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0; virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target) = 0; + virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *targetTemp) = 0; virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) = 0; virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) = 0; virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex) = 0; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 86a13cfe99..a3654a1bea 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -42,6 +42,7 @@ #include "qv4jsir_p.h" #include <private/qqmljsast_p.h> +#include <private/qqmlpropertycache_p.h> #include <QtCore/qtextstream.h> #include <QtCore/qdebug.h> #include <QtCore/qset.h> @@ -423,6 +424,10 @@ static const char *builtin_to_string(Name::Builtin b) return "builtin_setup_argument_object"; case V4IR::Name::builtin_qml_id_scope: return "builtin_qml_id_scope"; + case V4IR::Name::builtin_qml_scope_object: + return "builtin_qml_scope_object"; + case V4IR::Name::builtin_qml_context_object: + return "builtin_qml_context_object"; } return "builtin_(###FIXME)"; }; @@ -532,6 +537,8 @@ void Member::dump(QTextStream &out) const { base->dump(out); out << '.' << *name; + if (type == MemberOfQObject) + out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)"; } void Exp::dump(QTextStream &out, Mode) @@ -819,11 +826,18 @@ Expr *BasicBlock::MEMBER(Expr *base, const QString *name) return e; } -Expr *BasicBlock::QML_CONTEXT_ID_MEMBER(const QString &id, int objectId, quint32 line, quint32 column) +Expr *BasicBlock::QML_CONTEXT_ID_MEMBER(Expr *base, const QString *id, int objectId) { Member*e = function->New<Member>(); - Name *base = NAME(Name::builtin_qml_id_scope, line, column); - e->initQmlIdObject(base, function->newString(id), objectId); + Q_ASSERT(base->asName() && base->asName()->builtin == Name::builtin_qml_id_scope); + e->initQmlIdObject(base, id, objectId); + return e; +} + +Expr *BasicBlock::QML_QOBJECT_PROPERTY(Expr *base, const QString *id, QQmlPropertyData *property) +{ + Member*e = function->New<Member>(); + e->initMetaProperty(base, id, property); return e; } @@ -1013,12 +1027,30 @@ void CloneExpr::visitSubscript(Subscript *e) void CloneExpr::visitMember(Member *e) { - Member *m = static_cast<Member*>(block->MEMBER(clone(e->base), e->name)); - if (e->type == Member::MemberByObjectId) { - m->type = e->type; - m->objectId = e->objectId; + if (e->type == Member::MemberByName) + cloned = block->MEMBER(clone(e->base), e->name); + else if (e->type == Member::MemberByObjectId) + cloned = block->QML_CONTEXT_ID_MEMBER(clone(e->base), e->name, e->objectId); + else if (e->type == Member::MemberOfQObject) + cloned = block->QML_QOBJECT_PROPERTY(clone(e->base), e->name, e->property); + else + Q_ASSERT(!"Unimplemented!"); +} + +void QmlDependenciesCollector::visitMember(Member *e) { + e->base->accept(this); + if (e->type == Member::MemberByObjectId) + _usedIdObjects.insert(e->objectId); + else if (e->type == Member::MemberOfQObject + && !e->property->isFunction()) { // only non-functions have notifyIndex + + if (Name *base = e->base->asName()) { + if (base->builtin == Name::builtin_qml_context_object) + _usedContextProperties.insert(e->property); + else if (base->builtin == Name::builtin_qml_scope_object) + _usedScopeProperties.insert(e->property); + } } - cloned = m; } void QmlDependenciesCollector::visitPhi(Phi *s) { diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 1f69ac4964..7e7a972c54 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -72,6 +72,7 @@ QT_BEGIN_NAMESPACE class QTextStream; class QQmlType; +class QQmlPropertyData; namespace QV4 { struct ExecutionContext; @@ -323,7 +324,9 @@ struct Name: Expr { builtin_define_getter_setter, builtin_define_object_literal, builtin_setup_argument_object, - builtin_qml_id_scope + builtin_qml_id_scope, + builtin_qml_context_object, + builtin_qml_scope_object }; const QString *id; @@ -516,13 +519,15 @@ struct Member: Expr { enum MemberType { MemberByName, // QML extensions - MemberByObjectId // lookup in context's id values + MemberByObjectId, // lookup in context's id values + MemberOfQObject }; MemberType type; Expr *base; const QString *name; int objectId; + QQmlPropertyData *property; void init(Expr *base, const QString *name) { @@ -530,6 +535,7 @@ struct Member: Expr { this->base = base; this->name = name; this->objectId = -1; + this->property = 0; } void initQmlIdObject(Expr *base, const QString *name, int objectId) @@ -538,6 +544,15 @@ struct Member: Expr { this->base = base; this->name = name; this->objectId = objectId; + this->property = 0; + } + + void initMetaProperty(Expr *base, const QString *name, QQmlPropertyData *property) + { + this->type = MemberOfQObject; + this->base = base; + this->name = name; + this->property = property; } virtual void accept(ExprVisitor *v) { v->visitMember(this); } @@ -831,7 +846,8 @@ struct BasicBlock { Expr *NEW(Expr *base, ExprList *args = 0); Expr *SUBSCRIPT(Expr *base, Expr *index); Expr *MEMBER(Expr *base, const QString *name); - Expr *QML_CONTEXT_ID_MEMBER(const QString &id, int idIndex, quint32 line, quint32 column); + Expr *QML_CONTEXT_ID_MEMBER(Expr *base, const QString *id, int idIndex); + Expr *QML_QOBJECT_PROPERTY(Expr *base, const QString *id, QQmlPropertyData *property); Stmt *EXP(Expr *expr); @@ -933,10 +949,14 @@ private: struct QmlDependenciesCollector : public V4IR::StmtVisitor, V4IR::ExprVisitor { - QSet<int> run(Function *function) + void run(Function *function, QSet<int> *idObjectDependencies, QSet<QQmlPropertyData*> *contextPropertyDependencies, QSet<QQmlPropertyData*> *scopePropertyDependencies) { - QSet<int> dependencies; - qSwap(_usedIdObjects, dependencies); + QSet<int> idProperties; + QSet<QQmlPropertyData*> contextProperties; + QSet<QQmlPropertyData*> scopeProperties; + qSwap(_usedIdObjects, idProperties); + qSwap(_usedContextProperties, contextProperties); + qSwap(_usedScopeProperties, scopeProperties); for (int i = 0; i < function->basicBlocks.count(); ++i) { BasicBlock *bb = function->basicBlocks.at(i); for (int j = 0; j < bb->statements.count(); ++j) { @@ -944,12 +964,19 @@ struct QmlDependenciesCollector : public V4IR::StmtVisitor, V4IR::ExprVisitor s->accept(this); } } - qSwap(_usedIdObjects, dependencies); - return dependencies; + qSwap(_usedScopeProperties, scopeProperties); + qSwap(_usedContextProperties, contextProperties); + qSwap(_usedIdObjects, idProperties); + + *idObjectDependencies = idProperties; + *contextPropertyDependencies = contextProperties; + *scopePropertyDependencies = scopeProperties; } protected: QSet<int> _usedIdObjects; + QSet<QQmlPropertyData*> _usedContextProperties; + QSet<QQmlPropertyData*> _usedScopeProperties; virtual void visitConst(Const *) {} virtual void visitString(String *) {} @@ -976,11 +1003,7 @@ protected: e->index->accept(this); } - virtual void visitMember(Member *e) { - e->base->accept(this); - if (e->type == Member::MemberByObjectId) - _usedIdObjects.insert(e->objectId); - } + virtual void visitMember(Member *e); virtual void visitExp(Exp *s) {s->expr->accept(this);} virtual void visitMove(Move *s) { diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index e2d627b809..84efdbb920 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -340,6 +340,18 @@ protected: // IRDecoder addCall(); } + virtual void loadQmlContextObject(Temp *temp) + { + addDef(temp); + addCall(); + } + + virtual void loadQmlScopeObject(Temp *temp) + { + addDef(temp); + addCall(); + } + virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) { addDef(targetTemp); @@ -388,6 +400,13 @@ protected: // IRDecoder addCall(); } + virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, V4IR::Temp *target) + { + addDef(target); + addUses(base->asTemp(), Use::CouldHaveRegister); + addCall(); + } + virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) { addDef(target); |