diff options
author | Simon Hausmann <[email protected]> | 2013-10-18 15:36:40 +0200 |
---|---|---|
committer | The Qt Project <[email protected]> | 2013-10-20 21:11:54 +0200 |
commit | b93ddb95a74fff4bc61073b6b04e9dd7a7dc7f36 (patch) | |
tree | 5a3a1d29d2232fd10f5d9ffa3584e0ee22eab456 /src | |
parent | 6b2b62e903e1207255b0652b728ecaee6d51aea9 (diff) |
Qml JavaScript code generation cleanups
* Run the binding expressions, functions and signal handlers through
the V4 codegen _per_ component, and run the isel at the end for the
entire file. We need to do per-component codegen because we want to
set up the correct id and object scopes, which are different for the
root component and anonymous components.
* Changed V4IR::Module to allow for the concept of "qml modules" where
there is no root function defined. This is a logical consequence of
running v4 codegen multiple times with different input but the same
V4IR::Module.
Change-Id: Ib3a719f83507cbab7c2e4e145ccad5b663c795cf
Reviewed-by: Lars Knoll <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 117 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler_p.h | 26 |
8 files changed, 75 insertions, 91 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 887edc0b10..b485dcc240 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -140,7 +140,10 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) std::sort(runtimeFunctionsSortedByAddress.begin(), runtimeFunctionsSortedByAddress.end(), functionSortHelper); #endif - return runtimeFunctions[data->indexOfRootFunction]; + if (data->indexOfRootFunction != -1) + return runtimeFunctions[data->indexOfRootFunction]; + else + return 0; } void CompilationUnit::unlink() diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6784707607..bf6794e182 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -161,7 +161,7 @@ struct Unit uint offsetToRegexpTable; uint jsClassTableSize; uint offsetToJSClassTable; - uint indexOfRootFunction; + qint32 indexOfRootFunction; quint32 sourceFileIndex; QString stringAt(int idx) const { diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 8cd4c8e2d8..7d8c188927 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -198,6 +198,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize(); unit->jsClassTableSize = jsClasses.count(); unit->offsetToJSClassTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize(); + unit->indexOfRootFunction = -1; unit->sourceFileIndex = getStringId(irModule->fileName); // write strings and string table diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 500c2bd26f..483cb8e6f9 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -80,9 +80,6 @@ EvalISelFactory::~EvalISelFactory() QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData) { - Function *rootFunction = irModule->rootFunction; - if (!rootFunction) - return 0; for (int i = 0; i < irModule->functions.size(); ++i) run(i); diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 869bf4acaf..50afcf29c2 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -610,8 +610,10 @@ Function *Module::newFunction(const QString &name, Function *outer) Function *f = new Function(this, outer, name); functions.append(f); if (!outer) { - assert(!rootFunction); - rootFunction = f; + if (!isQmlModule) { + assert(!rootFunction); + rootFunction = f; + } } else { outer->nestedFunctions.append(f); } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index d0782a3a43..7b0ee52737 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -682,10 +682,14 @@ struct Q_QML_EXPORT Module { QVector<Function *> functions; Function *rootFunction; QString fileName; + bool isQmlModule; // implies rootFunction is always 0 Function *newFunction(const QString &name, Function *outer); - Module() : rootFunction(0) {} + Module() + : rootFunction(0) + , isQmlModule(false) + {} ~Module(); void setFileName(const QString &name); diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 697d255a3e..2cfb074aae 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -810,9 +810,8 @@ bool QQmlCompiler::compile(QQmlEngine *engine, this->unit = unit; this->unitRoot = root; this->output = out; - this->functionsToCompile.clear(); - this->compiledMetaMethods.clear(); - this->compiledSignalHandlers.clear(); + this->jsModule.reset(new QQmlJS::V4IR::Module); + this->jsModule->isQmlModule = true; // Compile types const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes(); @@ -919,58 +918,10 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree) if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) return; - const QQmlScript::Parser &parser = unit->parser(); - QQmlJS::Engine *jsEngine = parser.jsEngine(); - QQmlJS::MemoryPool *pool = jsEngine->pool(); - - foreach (JSBindingReference *root, allBindingReferenceRoots) { - for (JSBindingReference *b = root; b; b = b->nextReference) { - JSBindingReference &binding = *b; - - QQmlJS::AST::Node *node = binding.expression.asAST(); - // Always wrap this in an ExpressionStatement, to make sure that - // property var foo: function() { ... } results in a closure initialization. - if (!node->statementCast()) { - AST::ExpressionNode *expr = node->expressionCast(); - node = new (pool) AST::ExpressionStatement(expr); - } - - functionsToCompile.append(node); - binding.compiledIndex = functionsToCompile.count() - 1; - } - } - - if (!functionsToCompile.isEmpty()) { - JSCodeGen jsCodeGen; - - V4IR::Module jsModule; - const QString &sourceCode = jsEngine->code(); - AST::UiProgram *qmlRoot = parser.qmlRoot(); - - const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(unit->finalUrlString(), sourceCode, &jsModule, jsEngine, qmlRoot, functionsToCompile); - - foreach (JSBindingReference *root, allBindingReferenceRoots) { - for (JSBindingReference *b = root; b; b = b->nextReference) { - JSBindingReference &binding = *b; - functionsToCompile.append(binding.expression.asAST()); - binding.compiledIndex = runtimeFunctionIndices[binding.compiledIndex]; - } - } - - foreach (const CompiledMetaMethod &cmm, compiledMetaMethods) { - typedef QQmlVMEMetaData VMD; - VMD *vmd = (QQmlVMEMetaData *)cmm.obj->synthdata.data(); - VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex); - md.runtimeFunctionIndex = runtimeFunctionIndices.at(cmm.compiledFunctionIndex); - } - - foreach (const CompiledSignalHandlerExpression &expr, compiledSignalHandlers) { - expr.signal->signalData.functionIndex = runtimeFunctionIndices.at(expr.compiledHandlerIndex); - } - + if (!jsModule->functions.isEmpty()) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - QV4::Compiler::JSUnitGenerator jsUnitGenerator(&jsModule); - QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &jsModule, &jsUnitGenerator)); + QV4::Compiler::JSUnitGenerator jsUnitGenerator(jsModule.data()); + QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, jsModule.data(), &jsUnitGenerator)); isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/true); output->compilationUnit = jsUnit; @@ -1385,7 +1336,7 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj) } else if (v->type == Value::SignalExpression) { Instruction::StoreSignal store; - store.runtimeFunctionIndex = v->signalData.functionIndex; + store.runtimeFunctionIndex = compileState->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; @@ -1788,17 +1739,11 @@ bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *o prop->index = obj->metatype->originalClone(prop->index); 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() + compileState->functionsToCompile.append(funcDecl); + prop->values.first()->signalData.functionIndex = compileState->functionsToCompile.count() - 1; QString errorString; obj->metatype->signalParameterStringForJS(prop->index, &errorString); @@ -3305,12 +3250,12 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod vmd->methodCount++; md = methodData; - CompiledMetaMethod cmm; + QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod cmm; cmm.obj = obj; cmm.methodIndex = vmd->methodCount - 1; - functionsToCompile.append(s->funcDecl); - cmm.compiledFunctionIndex = functionsToCompile.count() - 1; - compiledMetaMethods.append(cmm); + compileState->functionsToCompile.append(s->funcDecl); + cmm.compiledFunctionIndex = compileState->functionsToCompile.count() - 1; + compileState->compiledMetaMethods.append(cmm); } if (aliasCount) @@ -3679,15 +3624,51 @@ bool QQmlCompiler::completeComponentBuild() aliasObject = compileState->aliasingObjects.next(aliasObject)) COMPILE_CHECK(buildDynamicMetaAliases(aliasObject)); + const QQmlScript::Parser &parser = unit->parser(); + QQmlJS::Engine *jsEngine = parser.jsEngine(); + QQmlJS::MemoryPool *pool = jsEngine->pool(); + for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { JSBindingReference &binding = *b; binding.dataType = BindingReference::QtScript; + QQmlJS::AST::Node *node = binding.expression.asAST(); + // Always wrap this in an ExpressionStatement, to make sure that + // property var foo: function() { ... } results in a closure initialization. + if (!node->statementCast()) { + AST::ExpressionNode *expr = node->expressionCast(); + node = new (pool) AST::ExpressionStatement(expr); + } + + compileState->functionsToCompile.append(node); + binding.compiledIndex = compileState->functionsToCompile.count() - 1; + if (componentStats) componentStats->componentStat.scriptBindings.append(b->value->location); } - allBindingReferenceRoots.append(compileState->bindings.first()); + + if (!compileState->functionsToCompile.isEmpty()) { + JSCodeGen jsCodeGen; + + 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); + compileState->runtimeFunctionIndices = runtimeFunctionIndices; + + for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { + JSBindingReference &binding = *b; + binding.compiledIndex = runtimeFunctionIndices[binding.compiledIndex]; + } + + 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); + } + } // Check pop()'s matched push()'s Q_ASSERT(compileState->objectDepth.depth() == 0); diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index c8e5c907e0..142d8c68b1 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -302,6 +302,16 @@ 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; }; }; @@ -461,21 +471,7 @@ private: int cachedComponentTypeRef; int cachedTranslationContextIndex; - QList<QQmlJS::AST::Node*> functionsToCompile; - QList<QQmlCompilerTypes::JSBindingReference*> allBindingReferenceRoots; - struct CompiledMetaMethod - { - QQmlScript::Object *obj; - int methodIndex; - int compiledFunctionIndex; // index in functionToCompile - }; - QList<CompiledMetaMethod> compiledMetaMethods; - struct CompiledSignalHandlerExpression - { - QQmlScript::Value *signal; - int compiledHandlerIndex; // index in functionsToCompile - }; - QList<CompiledSignalHandlerExpression> compiledSignalHandlers; + QScopedPointer<QQmlJS::V4IR::Module> jsModule; // Compiler component statistics. Only collected if QML_COMPILER_STATS=1 struct ComponentStat |