aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp41
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h26
-rw-r--r--src/qml/compiler/qv4codegen.cpp12
-rw-r--r--src/qml/compiler/qv4codegen_p.h5
-rw-r--r--src/qml/compiler/qv4compileddata_p.h13
-rw-r--r--src/qml/compiler/qv4compiler.cpp27
-rw-r--r--src/qml/compiler/qv4compiler_p.h1
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h9
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp5
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h1
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp8
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h1
-rw-r--r--src/qml/compiler/qv4isel_p.cpp5
-rw-r--r--src/qml/compiler/qv4isel_p.h1
-rw-r--r--src/qml/compiler/qv4jsir.cpp23
-rw-r--r--src/qml/compiler/qv4jsir_p.h89
-rw-r--r--src/qml/compiler/qv4regalloc.cpp6
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp8
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/qml/qqmlcompiler.cpp16
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp26
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h7
-rw-r--r--src/qml/qml/qqmlscript.cpp10
-rw-r--r--src/qml/qml/qqmlscript_p.h2
26 files changed, 320 insertions, 41 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 2aa5aa5a3c..cbf58599ac 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -1201,18 +1201,23 @@ int QmlUnitGenerator::getStringId(const QString &str) const
QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output)
{
return generateJSCodeForFunctionsAndBindings(fileName, output->code, &output->jsModule, &output->jsParserEngine,
- output->program, output->functions);
+ output->program, /* ### */output->program, output->functions);
}
QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
- QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, const QList<AST::Node*> &functions)
+ QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, AST::Node *contextRoot,
+ const QList<AST::Node*> &functions,
+ const ObjectIdMapping &objectIds)
{
+ this->idObjects = objectIds;
+
QVector<int> runtimeFunctionIndices(functions.size());
_module = jsModule;
_module->setFileName(fileName);
- QmlScanner scan(this, sourceCode);
- scan.begin(qmlRoot, QmlBinding);
+ ScanFunctions scan(this, sourceCode, GlobalCode);
+ scan.enterEnvironment(0, QmlBinding);
+ scan.enterQmlScope(qmlRoot, "context scope");
foreach (AST::Node *node, functions) {
Q_ASSERT(node != qmlRoot);
AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
@@ -1221,7 +1226,8 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fil
scan(function ? function->body : node);
scan.leaveEnvironment();
}
- scan.end();
+ scan.leaveEnvironment();
+ scan.leaveEnvironment();
_env = 0;
_function = _module->functions.at(defineFunction(QString("context scope"), qmlRoot, 0, 0));
@@ -1267,16 +1273,25 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fil
return runtimeFunctionIndices;
}
-
-void JSCodeGen::QmlScanner::begin(AST::Node *rootNode, CompilationMode compilationMode)
+V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col) const
{
- enterEnvironment(0, compilationMode);
- enterFunction(rootNode, "context scope", 0, 0, 0, /*isExpression*/false);
-}
+ V4IR::Expr *result = 0;
+ // Implement QML lookup semantics in the current file context.
-void JSCodeGen::QmlScanner::end()
-{
- leaveEnvironment();
+ // Look for IDs first.
+ foreach (const IdMapping &mapping, idObjects)
+ if (name == mapping.name) {
+ result = _block->QML_CONTEXT_ID_MEMBER(mapping.name, mapping.idIndex, line, col);
+ break;
+ }
+
+ if (result) {
+ _function->hasQmlDependencies = true;
+ return result;
+ }
+
+ // fall back to name lookup at run-time.
+ return 0;
}
SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate, ParsedQML *parsedQML,
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 1830b62772..0f4c2b145a 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -349,24 +349,24 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
: QQmlJS::Codegen(/*strict mode*/false)
{}
+ struct IdMapping
+ {
+ QString name;
+ int idIndex;
+ };
+ typedef QVector<IdMapping> ObjectIdMapping;
+
// Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output);
QVector<int> generateJSCodeForFunctionsAndBindings(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
- QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, const QList<AST::Node*> &functions);
-
-private:
- struct QmlScanner : public ScanFunctions
- {
- QmlScanner(JSCodeGen *cg, const QString &sourceCode)
- : ScanFunctions(cg, sourceCode, /*default program mode*/GlobalCode)
- , codeGen(cg)
- {}
+ QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, AST::Node *contextRoot, const QList<AST::Node*> &functions,
+ const ObjectIdMapping &objectIds = ObjectIdMapping());
- void begin(AST::Node *rootNode, CompilationMode compilationMode);
- void end();
+protected:
+ virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col) const;
- JSCodeGen *codeGen;
- };
+private:
+ ObjectIdMapping idObjects;
};
} // namespace QtQml
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 70dbdb1af5..cb15c2c885 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1448,6 +1448,10 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
f = f->outer;
}
+ // This hook allows implementing QML lookup semantics
+ if (V4IR::Expr *fallback = fallbackNameLookup(name, line, col))
+ return fallback;
+
if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding)
return _block->GLOBALNAME(name, line, col);
@@ -1456,6 +1460,14 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
}
+V4IR::Expr *Codegen::fallbackNameLookup(const QString &name, int line, int col) const
+{
+ Q_UNUSED(name)
+ Q_UNUSED(line)
+ Q_UNUSED(col)
+ return 0;
+}
+
bool Codegen::visit(IdentifierExpression *ast)
{
if (hasError)
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index dee9e13097..369df712c5 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -323,6 +323,8 @@ protected:
void variableDeclarationList(AST::VariableDeclarationList *ast);
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;
// nodes
virtual bool visit(AST::ArgumentList *ast);
@@ -466,6 +468,9 @@ protected:
void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
void leaveEnvironment();
+ void enterQmlScope(AST::Node *ast, const QString &name)
+ { enterFunction(ast, name, /*formals*/0, /*body*/0, /*expr*/0, /*isExpression*/false); }
+
protected:
using Visitor::visit;
using Visitor::endVisit;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index eda9751980..60a697e53e 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -232,6 +232,12 @@ struct Function
quint32 nInnerFunctions;
quint32 innerFunctionsOffset;
Location location;
+
+ // Qml Extensions Begin
+ quint32 nDependingIdObjects;
+ quint32 dependingIdObjectsOffset;
+ // Qml Extensions End
+
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
@@ -240,9 +246,12 @@ struct Function
const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
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); }
+
+ inline bool hasQmlDependencies() const { return nDependingIdObjects; }
- static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings) {
- return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings) * sizeof(quint32) + 7) & ~0x7;
+ 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;
}
};
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 2d14c0f69a..0b3e85352e 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -169,6 +169,14 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
registerString(*f->formals.at(i));
for (int i = 0; i < f->locals.size(); ++i)
registerString(*f->locals.at(i));
+
+ if (f->hasQmlDependencies) {
+ QQmlJS::V4IR::QmlDependenciesCollector depCollector;
+ QSet<int> idObjectDeps = depCollector.run(f);
+ if (!idObjectDeps.isEmpty())
+ qmlIdObjectDependenciesPerFunction.insert(f, idObjectDeps);
+ }
+
}
int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(),
@@ -184,7 +192,9 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd())
lineNumberMappingCount = lineNumberMapping->count() / 2;
- functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount);
+ const int qmlIdDepsCount = f->hasQmlDependencies ? qmlIdObjectDependenciesPerFunction.value(f).count() : 0;
+
+ functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount, qmlIdDepsCount);
}
const int totalSize = unitSize + functionDataSize + stringDataSize + jsClassDataSize;
@@ -309,6 +319,14 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
function->nInnerFunctions = irFunction->nestedFunctions.size();
function->innerFunctionsOffset = function->lineNumberMappingOffset + function->nLineNumberMappingEntries * 2 * sizeof(quint32);
+ function->nDependingIdObjects = 0;
+ QSet<int> qmlIdObjectDeps;
+ if (irFunction->hasQmlDependencies) {
+ qmlIdObjectDeps = qmlIdObjectDependenciesPerFunction.value(irFunction);
+ function->nDependingIdObjects = qmlIdObjectDeps.count();
+ function->dependingIdObjectsOffset = function->innerFunctionsOffset + function->nInnerFunctions * sizeof(quint32);
+ }
+
function->location.line = irFunction->line;
function->location.column = irFunction->column;
@@ -333,7 +351,12 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
- return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries);
+ // write QML dependencies
+ quint32 *writtenIdDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
+ foreach (int id, qmlIdObjectDeps)
+ *writtenIdDeps++ = id;
+
+ return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries, function->nDependingIdObjects);
}
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 42ef3242ea..40b3fe25c0 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -92,6 +92,7 @@ struct Q_QML_EXPORT JSUnitGenerator {
QList<QList<CompiledData::JSClassMember> > jsClasses;
uint jsClassDataSize;
uint headerSize;
+ QHash<QQmlJS::V4IR::Function *, QSet<int> > qmlIdObjectDependenciesPerFunction;
};
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 4c1fe360d1..f0b8983038 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -104,7 +104,8 @@ QT_BEGIN_NAMESPACE
F(AddNumberParams, addNumberParams) \
F(MulNumberParams, mulNumberParams) \
F(SubNumberParams, subNumberParams) \
- F(LoadThis, loadThis)
+ F(LoadThis, loadThis) \
+ F(LoadIdObject, loadIdObject)
#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
# define MOTH_THREADED_INTERPRETER
@@ -502,6 +503,11 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_loadIdObject {
+ MOTH_INSTR_HEADER
+ Param result;
+ int id;
+ };
instr_common common;
instr_ret ret;
@@ -559,6 +565,7 @@ union Instr
instr_mulNumberParams mulNumberParams;
instr_subNumberParams subNumberParams;
instr_loadThis loadThis;
+ instr_loadIdObject loadIdObject;
static int size(Type type);
};
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 461f028c99..1f00af3972 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -948,6 +948,11 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
#endif
}
+void InstructionSelection::loadIdObject(int id, V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_id_object, Assembler::ContextRegister, Assembler::TrustedImm32(id));
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 40d1aa5275..8178866656 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -1469,6 +1469,7 @@ protected:
virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
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 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);
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index a25da4d4ab..2db30aa7f8 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -419,6 +419,14 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
addInstruction(load);
}
+void InstructionSelection::loadIdObject(int id, V4IR::Temp *temp)
+{
+ Instruction::LoadIdObject load;
+ load.result = getResultParam(temp);
+ load.id = id;
+ addInstruction(load);
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
assert(sourceConst);
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index f5a14e15ae..df5c71ce8c 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -114,6 +114,7 @@ protected:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
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 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);
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 851d5661ff..b9341163de 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -135,7 +135,10 @@ void IRDecoder::visitMove(V4IR::Move *s)
return;
}
} else if (V4IR::Member *m = s->source->asMember()) {
- if (m->base->asTemp() || m->base->asConst()) {
+ if (m->type == V4IR::Member::MemberByObjectId) {
+ loadIdObject(m->objectId, 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 e3146add66..6e607d901c 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -140,6 +140,7 @@ public: // to implement by subclasses:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
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 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;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 1c9620e1f5..86a13cfe99 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -421,6 +421,8 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_define_object_literal";
case V4IR::Name::builtin_setup_argument_object:
return "builtin_setup_argument_object";
+ case V4IR::Name::builtin_qml_id_scope:
+ return "builtin_qml_id_scope";
}
return "builtin_(###FIXME)";
};
@@ -817,6 +819,14 @@ 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)
+{
+ Member*e = function->New<Member>();
+ Name *base = NAME(Name::builtin_qml_id_scope, line, column);
+ e->initQmlIdObject(base, function->newString(id), objectId);
+ return e;
+}
+
Stmt *BasicBlock::EXP(Expr *expr)
{
if (isTerminated())
@@ -1003,7 +1013,18 @@ void CloneExpr::visitSubscript(Subscript *e)
void CloneExpr::visitMember(Member *e)
{
- cloned = block->MEMBER(clone(e->base), e->name);
+ 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;
+ }
+ cloned = m;
+}
+
+void QmlDependenciesCollector::visitPhi(Phi *s) {
+ s->targetTemp->accept(this);
+ foreach (Expr *e, s->d->incoming)
+ e->accept(this);
}
} // end of namespace IR
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index fe8425ab71..1f69ac4964 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -322,7 +322,8 @@ struct Name: Expr {
builtin_define_array,
builtin_define_getter_setter,
builtin_define_object_literal,
- builtin_setup_argument_object
+ builtin_setup_argument_object,
+ builtin_qml_id_scope
};
const QString *id;
@@ -512,13 +513,31 @@ struct Subscript: Expr {
};
struct Member: Expr {
+ enum MemberType {
+ MemberByName,
+ // QML extensions
+ MemberByObjectId // lookup in context's id values
+ };
+
+ MemberType type;
Expr *base;
const QString *name;
+ int objectId;
void init(Expr *base, const QString *name)
{
+ this->type = MemberByName;
this->base = base;
this->name = name;
+ this->objectId = -1;
+ }
+
+ void initQmlIdObject(Expr *base, const QString *name, int objectId)
+ {
+ this->type = MemberByObjectId;
+ this->base = base;
+ this->name = name;
+ this->objectId = objectId;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
@@ -695,7 +714,8 @@ struct Function {
uint isNamedExpression : 1;
uint hasTry: 1;
uint hasWith: 1;
- uint unused : 26;
+ uint hasQmlDependencies : 1;
+ uint unused : 25;
// Location of declaration in source code (-1 if not specified)
int line;
@@ -716,6 +736,7 @@ struct Function {
, isNamedExpression(false)
, hasTry(false)
, hasWith(false)
+ , hasQmlDependencies(false)
, unused(0)
, line(-1)
, column(-1)
@@ -810,6 +831,7 @@ 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);
Stmt *EXP(Expr *expr);
@@ -909,6 +931,69 @@ private:
V4IR::Expr *cloned;
};
+struct QmlDependenciesCollector : public V4IR::StmtVisitor, V4IR::ExprVisitor
+{
+ QSet<int> run(Function *function)
+ {
+ QSet<int> dependencies;
+ qSwap(_usedIdObjects, dependencies);
+ for (int i = 0; i < function->basicBlocks.count(); ++i) {
+ BasicBlock *bb = function->basicBlocks.at(i);
+ for (int j = 0; j < bb->statements.count(); ++j) {
+ Stmt *s = bb->statements.at(j);
+ s->accept(this);
+ }
+ }
+ qSwap(_usedIdObjects, dependencies);
+ return dependencies;
+ }
+
+protected:
+ QSet<int> _usedIdObjects;
+
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); }
+ virtual void visitUnop(Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
+
+ virtual void visitCall(Call *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitNew(New *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitSubscript(Subscript *e) {
+ e->base->accept(this);
+ e->index->accept(this);
+ }
+
+ virtual void visitMember(Member *e) {
+ e->base->accept(this);
+ if (e->type == Member::MemberByObjectId)
+ _usedIdObjects.insert(e->objectId);
+ }
+
+ virtual void visitExp(Exp *s) {s->expr->accept(this);}
+ virtual void visitMove(Move *s) {
+ s->source->accept(this);
+ s->target->accept(this);
+ }
+
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { s->expr->accept(this); }
+ virtual void visitPhi(Phi *s);
+};
+
} // end of namespace IR
} // end of namespace QQmlJS
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 9c90388c9e..e2d627b809 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -334,6 +334,12 @@ protected: // IRDecoder
addDef(temp);
}
+ virtual void loadIdObject(int id, V4IR::Temp *temp)
+ {
+ addDef(temp);
+ addCall();
+ }
+
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
addDef(targetTemp);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 7c61a34190..523ef9c1e7 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -54,6 +54,7 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmlcontextwrapper_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
@@ -448,6 +449,9 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
callData->thisObject = obj.asReturnedValue();
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+
ExecutionContextSaver ctxSaver(context);
ScopedValue result(scope, f->function->code(ctx, f->function->codeData));
if (result->isObject())
@@ -474,6 +478,9 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
}
}
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(ctx->engine, f->function->compiledFunction);
+
ExecutionContextSaver ctxSaver(context);
return f->function->code(ctx, f->function->codeData);
}
@@ -535,6 +542,9 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
callData->thisObject = obj;
ExecutionContext *ctx = context->newCallContext(stackSpace, scope.alloc(f->varCount), f.getPointer(), callData);
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+
ExecutionContextSaver ctxSaver(context);
Scoped<Object> result(scope, f->function->code(ctx, f->function->codeData));
@@ -564,6 +574,9 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
}
}
+ if (f->function->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+
ExecutionContextSaver ctxSaver(context);
return f->function->code(ctx, f->function->codeData);
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 5678294115..0f23520610 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -51,6 +51,8 @@
#include "qv4function_p.h"
#include "private/qlocale_tools_p.h"
#include "qv4scopedvalue_p.h"
+#include <private/qqmlcontextwrapper_p.h>
+#include "qv4qobjectwrapper_p.h"
#include <QtCore/qmath.h>
#include <QtCore/qnumeric.h>
@@ -1175,6 +1177,12 @@ ReturnedValue __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, int id)
return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
}
+ReturnedValue __qmljs_get_id_object(ExecutionContext *ctx, int id)
+{
+ QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ return QObjectWrapper::wrap(ctx->engine, context->idValues[id].data());
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 54ade9384b..1ad7c84b9c 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -164,6 +164,8 @@ QV4::ReturnedValue __qmljs_construct_global_lookup(QV4::ExecutionContext *contex
QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index);
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);
+
// For each
QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in);
QV4::ReturnedValue __qmljs_foreach_next_property_name(const ValueRef foreach_iterator);
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index bd4bd65911..a5a94cd149 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -532,6 +532,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)
+ MOTH_BEGIN_INSTR(LoadIdObject)
+ VALUE(instr.result) = __qmljs_get_id_object(context, instr.id);
+ MOTH_END_INSTR(LoadIdObject)
+
#ifdef MOTH_THREADED_INTERPRETER
// nothing to do
#else
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 57114ebead..0462c0b61a 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -3654,7 +3654,21 @@ bool QQmlCompiler::completeComponentBuild()
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, compileState->functionsToCompile);
+ JSCodeGen::ObjectIdMapping idMapping;
+ if (compileState->ids.count() > 0) {
+ idMapping.reserve(compileState->ids.count());
+ for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) {
+ JSCodeGen::IdMapping m;
+ m.name = o->id;
+ m.idIndex = o->idIndex;
+ idMapping << m;
+ }
+ }
+
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine,
+ qmlRoot, compileState->root->astNode,
+ compileState->functionsToCompile,
+ idMapping);
compileState->runtimeFunctionIndices = runtimeFunctionIndices;
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index d3bcf6d3fd..5e798e20ee 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -47,9 +47,10 @@
#include <private/qv4engine_p.h>
#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4mm_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4compileddata_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
@@ -357,4 +358,27 @@ void QmlContextWrapper::destroy(Managed *that)
static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper();
}
+void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction)
+{
+ // Let the caller check and avoid the function call :)
+ Q_ASSERT(compiledFunction->hasQmlDependencies());
+
+ QQmlEnginePrivate *ep = engine->v8Engine->engine() ? QQmlEnginePrivate::get(engine->v8Engine->engine()) : 0;
+ if (!ep)
+ return;
+ QQmlEnginePrivate::PropertyCapture *capture = ep->propertyCapture;
+ if (!capture)
+ return;
+
+ QV4::Scope scope(engine);
+ 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);
+
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index 86ad4e5616..d85f440b15 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -59,11 +59,16 @@
#include <private/qv4value_p.h>
#include <private/qv4object_p.h>
#include <private/qqmlcontext_p.h>
+#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
+namespace CompiledData {
+struct Function;
+}
+
struct Q_QML_EXPORT QmlContextWrapper : Object
{
Q_MANAGED
@@ -86,6 +91,8 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
static void put(Managed *m, const StringRef name, const ValueRef value);
static void destroy(Managed *that);
+ static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction);
+
QV8Engine *v8; // ### temporary, remove
bool readOnly;
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index 9fd06aa934..6cb23ec07c 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -500,7 +500,7 @@ public:
protected:
- QQmlScript::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment,
+ QQmlScript::Object *defineObjectBinding(AST::Node *node, AST::UiQualifiedId *propertyName, bool onAssignment,
const QString &objectType,
AST::SourceLocation typeLocation,
LocationSpan location,
@@ -659,7 +659,8 @@ QString ProcessAST::asString(AST::UiQualifiedId *node) const
}
QQmlScript::Object *
-ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
+ProcessAST::defineObjectBinding(AST::Node *node,
+ AST::UiQualifiedId *propertyName,
bool onAssignment,
const QString &objectType,
AST::SourceLocation typeLocation,
@@ -731,6 +732,7 @@ ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
obj->type = _parser->findOrCreateTypeId(objectType, obj);
obj->typeReference = _parser->_refTypes.at(obj->type);
obj->location = location;
+ obj->astNode = node;
if (propertyCount) {
Property *prop = currentProperty();
@@ -1130,7 +1132,7 @@ bool ProcessAST::visit(AST::UiObjectDefinition *node)
const QString objectType = asString(node->qualifiedTypeNameId);
const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
- defineObjectBinding(/*propertyName = */ 0, false, objectType,
+ defineObjectBinding(node, /*propertyName = */ 0, false, objectType,
typeLocation, l, node->initializer);
return false;
@@ -1146,7 +1148,7 @@ bool ProcessAST::visit(AST::UiObjectBinding *node)
const QString objectType = asString(node->qualifiedTypeNameId);
const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
- defineObjectBinding(node->qualifiedId, node->hasOnToken, objectType,
+ defineObjectBinding(node, node->qualifiedId, node->hasOnToken, objectType,
typeLocation, l, node->initializer);
return false;
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
index 86bbc1fb3a..b36fdc8861 100644
--- a/src/qml/qml/qqmlscript_p.h
+++ b/src/qml/qml/qqmlscript_p.h
@@ -335,6 +335,8 @@ public:
QQmlPropertyCache *metatype;
+ QQmlJS::AST::Node *astNode; // responsible for the creation of this object
+
// The synthesized metaobject, if QML added signals or properties to
// this type. Otherwise null
QByteArray synthdata; // Generated by compiler