aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-18 15:36:40 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-20 21:11:54 +0200
commitb93ddb95a74fff4bc61073b6b04e9dd7a7dc7f36 (patch)
tree5a3a1d29d2232fd10f5d9ffa3584e0ee22eab456
parent6b2b62e903e1207255b0652b728ecaee6d51aea9 (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 <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qv4compileddata.cpp5
-rw-r--r--src/qml/compiler/qv4compileddata_p.h2
-rw-r--r--src/qml/compiler/qv4compiler.cpp1
-rw-r--r--src/qml/compiler/qv4isel_p.cpp3
-rw-r--r--src/qml/compiler/qv4jsir.cpp6
-rw-r--r--src/qml/compiler/qv4jsir_p.h6
-rw-r--r--src/qml/qml/qqmlcompiler.cpp117
-rw-r--r--src/qml/qml/qqmlcompiler_p.h26
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