aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-24 14:51:02 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-31 10:50:38 +0100
commit34c85bb56c92316a6ce1c79d25f9653fec14791c (patch)
tree6d3d43de33fa53a1353c52506e989ae126f1361b
parentbb7d26ebb0c2e7a9f06a030be8bfcd00e346e06f (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>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp84
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h16
-rw-r--r--src/qml/compiler/qv4codegen.cpp8
-rw-r--r--src/qml/compiler/qv4codegen_p.h7
-rw-r--r--src/qml/compiler/qv4compileddata_p.h14
-rw-r--r--src/qml/compiler/qv4compiler.cpp95
-rw-r--r--src/qml/compiler/qv4compiler_p.h10
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h26
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp15
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h3
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp25
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h3
-rw-r--r--src/qml/compiler/qv4isel_p.cpp10
-rw-r--r--src/qml/compiler/qv4isel_p.h3
-rw-r--r--src/qml/compiler/qv4jsir.cpp48
-rw-r--r--src/qml/compiler/qv4jsir_p.h49
-rw-r--r--src/qml/compiler/qv4regalloc.cpp19
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp63
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp24
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h3
-rw-r--r--src/qml/jsruntime/qv4script.cpp7
-rw-r--r--src/qml/jsruntime/qv4script_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp16
-rw-r--r--src/qml/qml/qqmlcompiler.cpp60
-rw-r--r--src/qml/qml/qqmlcompiler_p.h11
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp25
-rw-r--r--src/qml/qml/qqmlscript_p.h1
-rw-r--r--src/qml/qml/qqmltypeloader.cpp6
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp1
30 files changed, 535 insertions, 125 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);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index a4bfc93c36..22e2019112 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -329,16 +329,23 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (hasProperty)
*hasProperty = true;
- if (result->isFunction() && !result->isVarProperty()) {
- if (result->isVMEFunction()) {
+ return getProperty(ctx, result);
+}
+
+ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyData *property)
+{
+ QV4::Scope scope(ctx);
+
+ if (property->isFunction() && !property->isVarProperty()) {
+ if (property->isVMEFunction()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
Q_ASSERT(vmemo);
- return vmemo->vmeMethod(result->coreIndex);
- } else if (result->isV4Function()) {
+ return vmemo->vmeMethod(property->coreIndex);
+ } else if (property->isV4Function()) {
QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject());
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex, qmlcontextobject);
- } else if (result->isSignalHandler()) {
- QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, result->coreIndex));
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex, qmlcontextobject);
+ } else if (property->isSignalHandler()) {
+ QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, property->coreIndex));
QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect")));
QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect")));
@@ -347,45 +354,46 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
return handler.asReturnedValue();
} else {
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex);
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex);
}
}
QQmlEnginePrivate *ep = ctx->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->engine->v8Engine->engine()) : 0;
- if (result->hasAccessors()) {
+ if (property->hasAccessors()) {
QQmlNotifier *n = 0;
QQmlNotifier **nptr = 0;
- if (ep && ep->propertyCapture && result->accessors->notifier)
+ if (ep && ep->propertyCapture && property->accessors->notifier)
nptr = &n;
- QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *result, nptr));
+ QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *property, nptr));
- if (result->accessors->notifier) {
+ if (property->accessors->notifier) {
if (n)
ep->captureProperty(n);
} else {
- ep->captureProperty(m_object, result->coreIndex, result->notifyIndex);
+ ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
}
return rv.asReturnedValue();
}
- if (ep && !result->isConstant())
- ep->captureProperty(m_object, result->coreIndex, result->notifyIndex);
+ if (ep && !property->isConstant())
+ ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
- if (result->isVarProperty()) {
+ if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
Q_ASSERT(vmemo);
- return vmemo->vmeProperty(result->coreIndex);
- } else if (result->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *result, 0);
+ return vmemo->vmeProperty(property->coreIndex);
+ } else if (property->isDirect()) {
+ return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *property, 0);
} else {
- return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *result, 0);
+ return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *property, 0);
}
}
+
ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty)
{
QV4::Scope scope(ctx);
@@ -603,6 +611,21 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
}
}
+ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyIndex)
+{
+ if (QQmlData::wasDeleted(m_object))
+ return QV4::Encode::null();
+ QQmlData *ddata = QQmlData::get(m_object, /*create*/false);
+ if (!ddata)
+ return QV4::Encode::undefined();
+
+ QQmlPropertyCache *cache = ddata->propertyCache;
+ Q_ASSERT(cache);
+ QQmlPropertyData *property = cache->property(propertyIndex);
+ Q_ASSERT(property); // We resolved this property earlier, so it better exist!
+ return getProperty(ctx, property);
+}
+
ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object)
{
QQmlEngine *qmlEngine = engine->v8Engine->engine();
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index eadbacc096..6f886f0522 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -94,7 +94,11 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
using Object::get;
+ ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex);
+
private:
+ ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property);
+
static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object);
QObjectWrapper(ExecutionEngine *engine, QObject *object);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 0f23520610..aa8ab1c172 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1183,6 +1183,30 @@ ReturnedValue __qmljs_get_id_object(ExecutionContext *ctx, int id)
return QObjectWrapper::wrap(ctx->engine, context->idValues[id].data());
}
+ReturnedValue __qmljs_get_context_object(ExecutionContext *ctx)
+{
+ QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ return QObjectWrapper::wrap(ctx->engine, context->contextObject);
+}
+
+ReturnedValue __qmljs_get_scope_object(ExecutionContext *ctx)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ return QObjectWrapper::wrap(ctx->engine, c->getScopeObject());
+}
+
+ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QObjectWrapper> wrapper(scope, object);
+ if (!wrapper) {
+ ctx->throwTypeError(QStringLiteral("Cannot read property of null"));
+ return Encode::undefined();
+ }
+ return wrapper->getProperty(ctx, propertyIndex);
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index e04baadf53..464595a380 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -165,6 +165,9 @@ QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::Va
void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value);
QV4::ReturnedValue __qmljs_get_id_object(ExecutionContext *ctx, int id);
+QV4::ReturnedValue __qmljs_get_context_object(ExecutionContext *ctx);
+QV4::ReturnedValue __qmljs_get_scope_object(ExecutionContext *ctx);
+QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex);
// For each
QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in);
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 6e2c26edaf..f1903cf323 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -207,8 +207,7 @@ void Script::parse()
inheritedLocals.append(*i ? (*i)->toQString() : QString());
RuntimeCodegen cg(scope, strictMode);
- cg.generateFromProgram(sourceFile, sourceCode, program, &module,
- parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
+ cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals);
if (v4->hasException)
return;
@@ -286,7 +285,7 @@ Function *Script::function()
return vmFunction;
}
-CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, bool parseAsBinding, QList<QQmlError> *reportedErrors)
+CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
{
using namespace QQmlJS;
using namespace QQmlJS::AST;
@@ -330,7 +329,7 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const
}
QQmlJS::Codegen cg(/*strict mode*/false);
- cg.generateFromProgram(url.toString(), source, program, &module, parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::GlobalCode);
+ cg.generateFromProgram(url.toString(), source, program, &module, QQmlJS::Codegen::EvalCode);
errors = cg.errors();
if (!errors.isEmpty()) {
if (reportedErrors)
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 52ad4dd78c..657923062b 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -100,9 +100,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source,
- bool parseAsBinding,
- QList<QQmlError> *reportedErrors = 0);
+ static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject);
};
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 5a7b33a5d5..1797f0b2ee 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -305,6 +305,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
CHECK_EXCEPTION;
MOTH_END_INSTR(SetLookup)
+ MOTH_BEGIN_INSTR(LoadQObjectProperty)
+ STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex));
+ MOTH_END_INSTR(LoadQObjectProperty)
+
MOTH_BEGIN_INSTR(Push)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
@@ -628,9 +632,17 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)
- MOTH_BEGIN_INSTR(LoadIdObject)
+ MOTH_BEGIN_INSTR(LoadQmlIdObject)
VALUE(instr.result) = __qmljs_get_id_object(context, instr.id);
- MOTH_END_INSTR(LoadIdObject)
+ MOTH_END_INSTR(LoadQmlIdObject)
+
+ MOTH_BEGIN_INSTR(LoadQmlContextObject)
+ VALUE(instr.result) = __qmljs_get_context_object(context);
+ MOTH_END_INSTR(LoadContextObject)
+
+ MOTH_BEGIN_INSTR(LoadQmlScopeObject)
+ VALUE(instr.result) = __qmljs_get_scope_object(context);
+ MOTH_END_INSTR(LoadScopeObject)
#ifdef MOTH_THREADED_INTERPRETER
// nothing to do
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 58495bb1bf..3f57d7c2ef 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -1336,7 +1336,7 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
} else if (v->type == Value::SignalExpression) {
Instruction::StoreSignal store;
- store.runtimeFunctionIndex = compileState->runtimeFunctionIndices.at(v->signalData.functionIndex);
+ store.runtimeFunctionIndex = compileState->jsCompileData[v->signalData.signalScopeObject].runtimeFunctionIndices.at(v->signalData.functionIndex);
store.handlerName = output->indexForString(prop->name().toString());
store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index));
store.signalIndex = prop->index;
@@ -1738,12 +1738,15 @@ bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *o
//to ensure all parameters are available (see qqmlboundsignal constructor for more details)
prop->index = obj->metatype->originalClone(prop->index);
prop->values.first()->signalData.signalExpressionContextStack = ctxt.stack;
+ prop->values.first()->signalData.signalScopeObject = ctxt.object;
QList<QByteArray> parameters = obj->metatype->signalParameterNames(prop->index);
AST::FunctionDeclaration *funcDecl = convertSignalHandlerExpressionToFunctionDeclaration(unit->parser().jsEngine(), prop->values.first()->value.asAST(), propName.toString(), parameters);
- compileState->functionsToCompile.append(funcDecl);
- prop->values.first()->signalData.functionIndex = compileState->functionsToCompile.count() - 1;
+
+ ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[ctxt.object];
+ cd->functionsToCompile.append(funcDecl);
+ prop->values.first()->signalData.functionIndex = cd->functionsToCompile.count() - 1;
QString errorString;
obj->metatype->signalParameterStringForJS(prop->index, &errorString);
@@ -3250,12 +3253,13 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
vmd->methodCount++;
md = methodData;
- QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod cmm;
- cmm.obj = obj;
+ ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[obj];
+
+ ComponentCompileState::CompiledMetaMethod cmm;
cmm.methodIndex = vmd->methodCount - 1;
- compileState->functionsToCompile.append(s->funcDecl);
- cmm.compiledFunctionIndex = compileState->functionsToCompile.count() - 1;
- compileState->compiledMetaMethods.append(cmm);
+ cd->functionsToCompile.append(s->funcDecl);
+ cmm.compiledFunctionIndex = cd->functionsToCompile.count() - 1;
+ cd->compiledMetaMethods.append(cmm);
}
if (aliasCount)
@@ -3641,18 +3645,19 @@ bool QQmlCompiler::completeComponentBuild()
node = new (pool) AST::ExpressionStatement(expr);
}
- compileState->functionsToCompile.append(node);
- binding.compiledIndex = compileState->functionsToCompile.count() - 1;
+ ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object];
+ cd->functionsToCompile.append(node);
+ binding.compiledIndex = cd->functionsToCompile.count() - 1;
if (componentStats)
componentStats->componentStat.scriptBindings.append(b->value->location);
}
- if (!compileState->functionsToCompile.isEmpty()) {
+ if (!compileState->jsCompileData.isEmpty()) {
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot);
+ JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
JSCodeGen::ObjectIdMapping idMapping;
if (compileState->ids.count() > 0) {
@@ -3665,21 +3670,28 @@ bool QQmlCompiler::completeComponentBuild()
}
}
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(compileState->root->astNode,
- compileState->functionsToCompile,
- idMapping);
- compileState->runtimeFunctionIndices = runtimeFunctionIndices;
+ jsCodeGen.beginContextScope(idMapping, compileState->root->metatype);
- for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
- JSBindingReference &binding = *b;
- binding.compiledIndex = runtimeFunctionIndices[binding.compiledIndex];
+ for (QHash<QQmlScript::Object *, ComponentCompileState::PerObjectCompileData>::Iterator it = compileState->jsCompileData.begin();
+ it != compileState->jsCompileData.end(); ++it) {
+ QQmlScript::Object *scopeObject = it.key();
+ ComponentCompileState::PerObjectCompileData *cd = &it.value();
+
+ jsCodeGen.beginObjectScope(scopeObject->metatype);
+
+ cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile);
+
+ foreach (const QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod &cmm, cd->compiledMetaMethods) {
+ typedef QQmlVMEMetaData VMD;
+ VMD *vmd = (QQmlVMEMetaData *)scopeObject->synthdata.data();
+ VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex);
+ md.runtimeFunctionIndex = cd->runtimeFunctionIndices.at(cmm.compiledFunctionIndex);
+ }
}
- foreach (const QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod &cmm, compileState->compiledMetaMethods) {
- typedef QQmlVMEMetaData VMD;
- VMD *vmd = (QQmlVMEMetaData *)cmm.obj->synthdata.data();
- VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex);
- md.runtimeFunctionIndex = runtimeFunctionIndices.at(cmm.compiledFunctionIndex);
+ for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
+ JSBindingReference &binding = *b;
+ binding.compiledIndex = compileState->jsCompileData[binding.bindingContext.object].runtimeFunctionIndices[binding.compiledIndex];
}
}
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 142d8c68b1..2e3e6b8f4c 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -302,16 +302,21 @@ namespace QQmlCompilerTypes {
typedef QFieldList<O, &O::nextAliasingObject> AliasingObjectsList;
AliasingObjectsList aliasingObjects;
QQmlScript::Object *root;
- QList<QQmlJS::AST::Node*> functionsToCompile;
- QVector<int> runtimeFunctionIndices;
struct CompiledMetaMethod
{
- QQmlScript::Object *obj;
int methodIndex;
int compiledFunctionIndex; // index in functionToCompile
};
+
QList<CompiledMetaMethod> compiledMetaMethods;
+ struct PerObjectCompileData
+ {
+ QList<QQmlJS::AST::Node*> functionsToCompile;
+ QVector<int> runtimeFunctionIndices;
+ QVector<CompiledMetaMethod> compiledMetaMethods;
+ };
+ QHash<QQmlScript::Object *, PerObjectCompileData> jsCompileData;
};
};
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index 5e798e20ee..832d9421c2 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -374,10 +374,27 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C
QV4::Scoped<QmlContextWrapper> contextWrapper(scope, engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
QQmlContextData *qmlContext = contextWrapper->getContext();
- const quint32 *dependency = compiledFunction->qmlIdObjectDependencyTable();
- const int dependencyCount = compiledFunction->nDependingIdObjects;
- for (int i = 0; i < dependencyCount; ++i, ++dependency)
- capture->captureProperty(&qmlContext->idValues[*dependency].bindings);
+ const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
+ const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
+ for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency)
+ capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings);
+
+ const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
+ const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
+ for (int i = 0; i < contextPropertyDependencyCount; ++i) {
+ const int propertyIndex = *contextPropertyDependency++;
+ const int notifyIndex = *contextPropertyDependency++;
+ capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex);
+ }
+
+ QObject *scopeObject = contextWrapper->getScopeObject();
+ const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
+ const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
+ for (int i = 0; i < scopePropertyDependencyCount; ++i) {
+ const int propertyIndex = *scopePropertyDependency++;
+ const int notifyIndex = *scopePropertyDependency++;
+ capture->captureProperty(scopeObject, propertyIndex, notifyIndex);
+ }
}
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
index b36fdc8861..fac31add5c 100644
--- a/src/qml/qml/qqmlscript_p.h
+++ b/src/qml/qml/qqmlscript_p.h
@@ -229,6 +229,7 @@ public:
// Used by compiler
struct SignalData {
int signalExpressionContextStack;
+ Object *signalScopeObject;
int functionIndex; // before gen() index in functionsToCompile, then index in runtime functions
};
union {
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 6f718e5b5b..b3bc5eb4a1 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2357,8 +2357,8 @@ void QQmlTypeData::compile()
// Compile JS binding expressions and signal handlers
- JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program);
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(/*### context root*/0, parsedQML->functions);
+ JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
@@ -2920,7 +2920,7 @@ void QQmlScriptBlob::done()
QList<QQmlError> errors;
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- m_scriptData->m_precompiledScript = QV4::Script::precompile(v4, m_scriptData->url, m_source, /*parseAsBinding*/true, &errors);
+ m_scriptData->m_precompiledScript = QV4::Script::precompile(v4, m_scriptData->url, m_source, &errors);
if (m_scriptData->m_precompiledScript)
m_scriptData->m_precompiledScript->ref();
m_source.clear();
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 5caf5722af..3216f5977d 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -1304,6 +1304,7 @@ void tst_qqmlecmascript::scope()
QVERIFY(object != 0);
QCOMPARE(object->property("test1").toBool(), true);
+ QEXPECT_FAIL("", "Properties resolvable at compile time come before the global object, which is not 100% compatible with older QML versions", Continue);
QCOMPARE(object->property("test2").toBool(), true);
QCOMPARE(object->property("test3").toBool(), true);