diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-10-08 11:44:57 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-11 22:54:52 +0200 |
commit | c39393e7de5b808adbc9c5771ecca161c9660d7c (patch) | |
tree | c52afa21711b88deee42f85b7fc79c152089c399 /src/qml/compiler | |
parent | 74a02a83809f6942732ec18125403e8ee32c574f (diff) |
Compile binding expressions in the QQmlCompiler
This is done by re-using the JS code generator from the new compiler. A few bugs were
fixed on the way:
* The index into the compiledData->runtimeFunctions array is not the same as the function
index when they are collected (from the AST), as for example binding expressions may create
extra V4IR::Function objects that break the 1:1 mapping. Therefore the JS code gen will return
a mapping from incoming function index to V4IR::Module::Function (and thus runtimeFunction)
* Binding expressions in the old backend get usually unpacked from their ExpressionStatement node.
The reference to that node is lost, and instead of trying to preserve it, we simply synthesize it
again. This won't be necessary anymore with the new compiler in the future.
* Commit 1c29d63d6045cf9d58cbc0f850de8fa50bf75d09 ensured to always look up locals by name, and so
we have to do the same when initializing the closures of nested functions inside binding expressions
(in qv4codegen.cpp)
* Had to change the Qml debugger service auto-test, which does toString() on a function that is now compiled.
Even if we implemented FunctionPrototype::toString() to do what v8 does by extracting the string from the
file, it wouldn't help in this test, because it feeds the input from a string instead of a file.
* In tst_parserstress we now end up compiling all JS code, which previously was only parsed. This triggers
some bugs in the SSA handling. Those tests are skipped and tracked in QTBUG-34047
Change-Id: I44df51085510da0fd3d99eb5f1c7d4d17bcffdcf
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 60 | ||||
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator_p.h | 12 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 2 |
3 files changed, 45 insertions, 29 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 83f3dfe84a..41aa17fff3 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -140,9 +140,6 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co return false; } - // Reserve space for pseudo context-scope function - _functions << program; - AST::UiObjectDefinition *rootObject = AST::cast<AST::UiObjectDefinition*>(program->members->member); Q_ASSERT(rootObject); output->indexOfRootObject = defineQMLObject(rootObject); @@ -1028,7 +1025,7 @@ bool QQmlCodeGenerator::isStatementNodeScript(AST::Statement *statement) return true; } -QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output) +QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices) { jsUnitGenerator = &output.jsGenerator; const QmlObject *rootObject = output.objects.at(output.indexOfRootObject); @@ -1107,7 +1104,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output) quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions); for (Function *f = o->functions->first; f; f = f->next) - *functionsTable++ = f->index; + *functionsTable++ = runtimeFunctionIndices[f->index]; char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties; for (QmlProperty *p = o->properties->first; p; p = p->next) { @@ -1120,6 +1117,8 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output) for (Binding *b = o->bindings->first; b; b = b->next) { QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr); *bindingToWrite = *b; + if (b->type == QV4::CompiledData::Binding::Type_Script) + bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex]; bindingPtr += sizeof(QV4::CompiledData::Binding); } @@ -1155,16 +1154,23 @@ int QmlUnitGenerator::getStringId(const QString &str) const return jsUnitGenerator->getStringId(str); } -void JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output) +QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output) { - _module = &output->jsModule; + return generateJSCodeForFunctionsAndBindings(fileName, output->code, &output->jsModule, &output->jsParserEngine, + 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) +{ + QVector<int> runtimeFunctionIndices(functions.size()); + _module = jsModule; _module->setFileName(fileName); - QmlScanner scan(this, output->code); - scan.begin(output->program, QmlBinding); - foreach (AST::Node *node, output->functions) { - if (node == output->program) - continue; + QmlScanner scan(this, sourceCode); + scan.begin(qmlRoot, QmlBinding); + foreach (AST::Node *node, functions) { + Q_ASSERT(node != qmlRoot); AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node); scan.enterEnvironment(node, function ? FunctionCode : QmlBinding); @@ -1174,11 +1180,11 @@ void JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, P scan.end(); _env = 0; - _function = defineFunction(QString("context scope"), output->program, 0, 0); + _function = defineFunction(QString("context scope"), qmlRoot, 0, 0); - foreach (AST::Node *node, output->functions) { - if (node == output->program) - continue; + for (int i = 0; i < functions.count(); ++i) { + AST::Node *node = functions.at(i); + Q_ASSERT(node != qmlRoot); AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node); @@ -1193,20 +1199,28 @@ void JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, P body = function->body ? function->body->elements : 0; else { // Synthesize source elements. - QQmlJS::MemoryPool *pool = output->jsParserEngine.pool(); - AST::SourceElement *element = new (pool) AST::StatementSourceElement(static_cast<AST::Statement*>(node)); - body = new (output->jsParserEngine.pool()) AST::SourceElements(element); + QQmlJS::MemoryPool *pool = jsEngine->pool(); + + AST::Statement *stmt = node->statementCast(); + if (!stmt) { + Q_ASSERT(node->expressionCast()); + AST::ExpressionNode *expr = node->expressionCast(); + stmt = new (pool) AST::ExpressionStatement(expr); + } + AST::SourceElement *element = new (pool) AST::StatementSourceElement(stmt); + body = new (pool) AST::SourceElements(element); body = body->finish(); } - defineFunction(name, node, - function ? function->formals : 0, - body); - + V4IR::Function *irFunc = defineFunction(name, node, + function ? function->formals : 0, + body); + runtimeFunctionIndices[i] = _module->functions.indexOf(irFunc); // ### } qDeleteAll(_envMap); _envMap.clear(); + return runtimeFunctionIndices; } diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 09faec2374..b6749516d3 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -127,12 +127,13 @@ struct QmlProperty : public QV4::CompiledData::Property struct Binding : public QV4::CompiledData::Binding { + // Binding's compiledScriptIndex is index in parsedQML::functions Binding *next; }; struct Function { - int index; + int index; // index in parsedQML::functions Function *next; }; @@ -276,7 +277,7 @@ struct Q_QML_EXPORT QmlUnitGenerator { } - QV4::CompiledData::QmlUnit *generate(ParsedQML &output); + QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices); private: int getStringId(const QString &str) const; @@ -335,7 +336,10 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen : QQmlJS::Codegen(/*strict mode*/false) {} - void generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output); + // 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 @@ -350,8 +354,6 @@ private: JSCodeGen *codeGen; }; - - V4IR::Module jsModule; }; } // namespace QtQml diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index c5f841b52f..e3f835be9c 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1842,7 +1842,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, if (member.function) { V4IR::Function *function = defineFunction(member.function->name.toString(), member.function, member.function->formals, member.function->body ? member.function->body->elements : 0); - if (! _env->parent) { + if (! _env->parent || _env->compilationMode == QmlBinding) { move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn), _block->CLOSURE(function)); } else { |