From 28f67263a181e2d99b2c240f9d698bf64100ac92 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 9 Oct 2013 09:37:08 +0200 Subject: 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 --- src/qml/qml/qqmlcompiler.cpp | 58 +++++++++++++++++++++++++++++++++++++++-- src/qml/qml/qqmlcompiler_p.h | 6 +++++ src/qml/qml/qqmlinstruction_p.h | 1 + src/qml/qml/qqmlscript_p.h | 6 ++++- src/qml/qml/qqmlvme.cpp | 11 +++++--- 5 files changed, 75 insertions(+), 7 deletions(-) (limited to 'src/qml') 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 &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 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 ¶meters) +{ + QQmlJS::MemoryPool *pool = jsEngine->pool(); + + AST::FormalParameterList *paramList = 0; + foreach (const QByteArray ¶m, 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 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 compiledMetaMethods; + struct CompiledSignalHandlerExpression + { + QQmlScript::Value *signal; + int compiledHandlerIndex; // index in functionsToCompile + }; + QList 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 *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) -- cgit v1.2.3