aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-09 09:37:08 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-11 22:55:08 +0200
commit28f67263a181e2d99b2c240f9d698bf64100ac92 (patch)
tree3c7c6287e00d6032ff53a78b7a9b0caa51cc9d23 /src/qml
parent774963f52f569e637f45d6c6079121253e54b61b (diff)
Compile signal handler expressions in the loader thread
Handle them similar to function declarations, except that we need to synthesize the expression into a function declaration that includes the signal parameter names. This is done quite similar to the code path in the new compiler. Change-Id: I751081f7f1052692da6e2ed60c7f5c017372d829 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/qml/qqmlcompiler.cpp58
-rw-r--r--src/qml/qml/qqmlcompiler_p.h6
-rw-r--r--src/qml/qml/qqmlinstruction_p.h1
-rw-r--r--src/qml/qml/qqmlscript_p.h6
-rw-r--r--src/qml/qml/qqmlvme.cpp11
5 files changed, 75 insertions, 7 deletions
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index d14c790aad..697d255a3e 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -812,6 +812,7 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
this->output = out;
this->functionsToCompile.clear();
this->compiledMetaMethods.clear();
+ this->compiledSignalHandlers.clear();
// Compile types
const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
@@ -963,6 +964,10 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
md.runtimeFunctionIndex = runtimeFunctionIndices.at(cmm.compiledFunctionIndex);
}
+ foreach (const CompiledSignalHandlerExpression &expr, compiledSignalHandlers) {
+ expr.signal->signalData.functionIndex = runtimeFunctionIndices.at(expr.compiledHandlerIndex);
+ }
+
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Compiler::JSUnitGenerator jsUnitGenerator(&jsModule);
QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &jsModule, &jsUnitGenerator));
@@ -1380,11 +1385,12 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
} else if (v->type == Value::SignalExpression) {
Instruction::StoreSignal store;
+ store.runtimeFunctionIndex = v->signalData.functionIndex;
store.handlerName = output->indexForString(prop->name().toString());
store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index));
store.signalIndex = prop->index;
store.value = output->indexForString(v->value.asScript());
- store.context = v->signalExpressionContextStack;
+ store.context = v->signalData.signalExpressionContextStack;
store.line = v->location.start.line;
store.column = v->location.start.column;
output->addInstruction(store);
@@ -1678,6 +1684,42 @@ int QQmlCompiler::translationContextIndex()
return cachedTranslationContextIndex;
}
+static AST::FunctionDeclaration *convertSignalHandlerExpressionToFunctionDeclaration(QQmlJS::Engine *jsEngine,
+ AST::Node *node,
+ const QString &signalName,
+ const QList<QByteArray> &parameters)
+{
+ QQmlJS::MemoryPool *pool = jsEngine->pool();
+
+ AST::FormalParameterList *paramList = 0;
+ foreach (const QByteArray &param, parameters) {
+ QStringRef paramNameRef = jsEngine->newStringRef(QString::fromUtf8(param));
+
+ if (paramList)
+ paramList = new (pool) AST::FormalParameterList(paramList, paramNameRef);
+ else
+ paramList = new (pool) AST::FormalParameterList(paramNameRef);
+ }
+
+ if (paramList)
+ paramList = paramList->finish();
+
+ AST::Statement *statement = node->statementCast();
+ if (!statement) {
+ AST::ExpressionNode *expr = node->expressionCast();
+ Q_ASSERT(expr);
+ statement = new (pool) AST::ExpressionStatement(expr);
+ }
+ AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement);
+ AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement);
+ elements = elements->finish();
+
+ AST::FunctionBody *body = new (pool) AST::FunctionBody(elements);
+
+ AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine->newStringRef(signalName), paramList, body);
+ return functionDeclaration;
+}
+
bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
const BindingContext &ctxt)
{
@@ -1744,7 +1786,19 @@ bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *o
//all handlers should be on the original, rather than cloned signals in order
//to ensure all parameters are available (see qqmlboundsignal constructor for more details)
prop->index = obj->metatype->originalClone(prop->index);
- prop->values.first()->signalExpressionContextStack = ctxt.stack;
+ prop->values.first()->signalData.signalExpressionContextStack = ctxt.stack;
+
+ CompiledSignalHandlerExpression expr;
+ expr.signal = prop->values.first();
+
+ QList<QByteArray> parameters = obj->metatype->signalParameterNames(prop->index);
+
+ AST::FunctionDeclaration *funcDecl = convertSignalHandlerExpressionToFunctionDeclaration(unit->parser().jsEngine(), prop->values.first()->value.asAST(), propName.toString(), parameters);
+ functionsToCompile.append(funcDecl);
+
+ expr.compiledHandlerIndex = functionsToCompile.count() - 1;
+ compiledSignalHandlers.append(expr);
+ prop->values.first()->signalData.functionIndex = 0; // To be filled in before gen()
QString errorString;
obj->metatype->signalParameterStringForJS(prop->index, &errorString);
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 1d1306fba4..c8e5c907e0 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -470,6 +470,12 @@ private:
int compiledFunctionIndex; // index in functionToCompile
};
QList<CompiledMetaMethod> compiledMetaMethods;
+ struct CompiledSignalHandlerExpression
+ {
+ QQmlScript::Value *signal;
+ int compiledHandlerIndex; // index in functionsToCompile
+ };
+ QList<CompiledSignalHandlerExpression> compiledSignalHandlers;
// Compiler component statistics. Only collected if QML_COMPILER_STATS=1
struct ComponentStat
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index 14a038783d..01b6fa41a4 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -392,6 +392,7 @@ union QQmlInstruction
};
struct instr_storeSignal {
QML_INSTR_HEADER
+ int runtimeFunctionIndex;
int handlerName;
int parameters;
int signalIndex;
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
index 7aecba993b..86bbc1fb3a 100644
--- a/src/qml/qml/qqmlscript_p.h
+++ b/src/qml/qml/qqmlscript_p.h
@@ -227,9 +227,13 @@ public:
LocationSpan location;
// Used by compiler
+ struct SignalData {
+ int signalExpressionContextStack;
+ int functionIndex; // before gen() index in functionsToCompile, then index in runtime functions
+ };
union {
QQmlCompilerTypes::BindingReference *bindingReference;
- int signalExpressionContextStack;
+ SignalData signalData;
};
// Used in Property::ValueList lists
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 21f7ce4cab..c1c05fac11 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -777,13 +777,16 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QObject *target = objects.top();
QObject *context = objects.at(objects.count() - 1 - instr.context);
+ QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, context, objects.count() - 1 - instr.context);
+
+ QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.runtimeFunctionIndex];
+
+ tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction);
+
QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine);
QQmlBoundSignalExpression *expr =
new QQmlBoundSignalExpression(target, instr.signalIndex,
- CTXT, context, PRIMITIVES.at(instr.value),
- COMP->name, instr.line, instr.column,
- PRIMITIVES.at(instr.handlerName),
- PRIMITIVES.at(instr.parameters));
+ CTXT, context, tmpValue);
bs->takeExpression(expr);
QML_END_INSTR(StoreSignal)