aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-02-25 16:36:41 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-03-02 14:48:43 +0100
commit963875db263e4d1a04e03c4bb4fc20542bc8c21e (patch)
treecbb63607672e9d302d30389c8fe7553b27807b1f
parent278ca02350c68a78c89bb34d99ee65968372a5fd (diff)
[new compiler] Compile functions and bindings in appropriate scopes
This enables accelerated property access also for this code path. Change-Id: Iafb177b1fe7878e6c54cfb258f2e8d8ea32aa59e Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp60
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h69
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp138
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h27
-rw-r--r--src/qml/qml/qqmlcompiler.cpp8
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp4
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h4
-rw-r--r--src/qml/types/qqmllistmodel.cpp5
8 files changed, 250 insertions, 65 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 35f303c9fc..56e5d7183d 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -79,6 +79,8 @@ void QmlObject::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
+ functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
+ runtimeFunctionIndices = 0;
declarationsOverride = 0;
}
@@ -91,14 +93,13 @@ void QmlObject::dump(DebugStream &out)
out << "}" << endl;
}
-QString QmlObject::sanityCheckFunctionNames(const QList<CompiledFunctionOrExpression> &allFunctions, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
+QString QmlObject::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
{
QSet<int> functionNames;
for (Function *f = functions->first; f; f = f->next) {
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(allFunctions.at(f->index).node);
+ QQmlJS::AST::FunctionDeclaration *function = f->functionDeclaration;
Q_ASSERT(function);
*errorLocation = function->identifierToken;
- QString name = function->name.toString();
if (functionNames.contains(f->nameIndex))
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
@@ -108,6 +109,7 @@ QString QmlObject::sanityCheckFunctionNames(const QList<CompiledFunctionOrExpres
return tr("Duplicate method name");
}
+ const QString name = function->name.toString();
if (name.at(0).isUpper())
return tr("Method names cannot begin with an upper case letter");
if (illegalNames.contains(name))
@@ -249,7 +251,6 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
this->pool = output->jsParserEngine.pool();
this->jsGenerator = &output->jsGenerator;
@@ -278,7 +279,6 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
return errors.isEmpty();
}
@@ -448,7 +448,7 @@ bool QQmlCodeGenerator::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifi
return false;
QQmlJS::AST::SourceLocation loc;
- QString error = obj->sanityCheckFunctionNames(_functions, illegalNames, &loc);
+ QString error = obj->sanityCheckFunctionNames(illegalNames, &loc);
if (!error.isEmpty()) {
recordError(loc, error);
return false;
@@ -869,13 +869,18 @@ bool QQmlCodeGenerator::visit(QQmlJS::AST::UiPublicMember *node)
bool QQmlCodeGenerator::visit(QQmlJS::AST::UiSourceElement *node)
{
if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
- _functions << funDecl;
+ CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
+ foe->node = funDecl;
+ foe->nameIndex = registerString(funDecl->name.toString());
+ foe->disableAcceleratedLookups = false;
+ const int index = _object->functionsAndExpressions->append(foe);
+
Function *f = New<Function>();
f->functionDeclaration = funDecl;
QQmlJS::AST::SourceLocation loc = funDecl->identifierToken;
f->location.line = loc.startLine;
f->location.column = loc.startColumn;
- f->index = _functions.size() - 1;
+ f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
_object->appendFunction(f);
} else {
@@ -970,8 +975,13 @@ void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, QQm
// Do binding instead
if (binding->type == QV4::CompiledData::Binding::Type_Invalid) {
binding->type = QV4::CompiledData::Binding::Type_Script;
- _functions << statement;
- binding->value.compiledScriptIndex = _functions.size() - 1;
+
+ CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
+ expr->node = statement;
+ expr->nameIndex = 0;
+ expr->disableAcceleratedLookups = false;
+ const int index = bindingsTarget()->functionsAndExpressions->append(expr);
+ binding->value.compiledScriptIndex = index;
binding->stringIndex = registerString(asStringRef(statement).toString());
}
}
@@ -1259,7 +1269,7 @@ bool QQmlCodeGenerator::isStatementNodeScript(QQmlJS::AST::Statement *statement)
return true;
}
-QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices)
+QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
{
jsUnitGenerator = &output.jsGenerator;
int unitSize = 0;
@@ -1337,7 +1347,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
- *functionsTable++ = runtimeFunctionIndices[f->index];
+ *functionsTable++ = o->runtimeFunctionIndices->at(f->index);
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
for (const QmlProperty *p = o->firstProperty(); p; p = p->next) {
@@ -1347,11 +1357,11 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
}
char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBindingNoAlias);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isSignalHandler);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isAttachedProperty);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isGroupProperty);
- bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBindingToAlias);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isAttachedProperty);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isGroupProperty);
+ bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingToAlias);
Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount()));
quint32 *signalOffsetTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToSignals);
@@ -1389,7 +1399,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
return qmlUnit;
}
-char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const
+char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, BindingFilter filter) const
{
for (const Binding *b = o->firstBinding(); b; b = b->next) {
if (!(b->*(filter))())
@@ -1397,7 +1407,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, const QVec
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];
+ bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices->at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
return bindingPtr;
@@ -1409,12 +1419,13 @@ int QmlUnitGenerator::getStringId(const QString &str) const
}
JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, IR::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
+ QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QStringList &stringPool)
: QQmlJS::Codegen(/*strict mode*/false)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
, qmlRoot(qmlRoot)
, imports(imports)
+ , stringPool(stringPool)
, _disableAcceleratedLookups(false)
, _contextObject(0)
, _scopeObject(0)
@@ -1475,8 +1486,8 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QString name;
if (function)
name = function->name.toString();
- else if (!qmlFunction.name.isEmpty())
- name = qmlFunction.name;
+ else if (qmlFunction.nameIndex != 0)
+ name = stringPool.value(qmlFunction.nameIndex);
else
name = QStringLiteral("%qml-expression-entry");
@@ -1988,7 +1999,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (paramList)
paramList = paramList->finish();
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex].node);
+ CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
+ QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement);
QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement);
elements = elements->finish();
@@ -1997,7 +2009,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
QQmlJS::AST::FunctionDeclaration *functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(jsEngine.newStringRef(propertyName), paramList, body);
- parsedQML->functions[binding->value.compiledScriptIndex] = functionDeclaration;
+ foe->node = functionDeclaration;
binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
}
return true;
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 7f27bded20..304df224c0 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -136,6 +136,49 @@ struct PoolList
++count;
}
}
+
+ T *slowAt(int index) const
+ {
+ T *result = first;
+ while (index > 0 && result) {
+ result = result->next;
+ --index;
+ }
+ return result;
+ }
+};
+
+template <typename T>
+class FixedPoolArray
+{
+ T *data;
+ int count;
+public:
+
+ void init(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
+ {
+ count = vector.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+
+ if (QTypeInfo<T>::isComplex) {
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(vector.at(i));
+ } else {
+ memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
+ }
+ }
+
+ const T &at(int index) const {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ int indexOf(const T &value) const {
+ for (int i = 0; i < count; ++i)
+ if (data[i] == value)
+ return i;
+ return -1;
+ }
};
struct QmlObject;
@@ -163,7 +206,7 @@ struct QmlProperty : public QV4::CompiledData::Property
struct Binding : public QV4::CompiledData::Binding
{
- // Binding's compiledScriptIndex is index in parsedQML::functions
+ // Binding's compiledScriptIndex is index in object's functionsAndExpressions
Binding *next;
};
@@ -172,7 +215,7 @@ struct Function
QQmlJS::AST::FunctionDeclaration *functionDeclaration;
QV4::CompiledData::Location location;
int nameIndex;
- int index; // index in parsedQML::functions
+ quint32 index; // index in parsedQML::functions
Function *next;
};
@@ -180,15 +223,20 @@ struct CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
: node(0)
+ , nameIndex(0)
, disableAcceleratedLookups(false)
+ , next(0)
{}
CompiledFunctionOrExpression(QQmlJS::AST::Node *n)
: node(n)
+ , nameIndex(0)
, disableAcceleratedLookups(false)
+ , next(0)
{}
QQmlJS::AST::Node *node; // FunctionDeclaration, Statement or Expression
- QString name;
+ quint32 nameIndex;
bool disableAcceleratedLookups;
+ CompiledFunctionOrExpression *next;
};
struct QmlObject
@@ -219,7 +267,7 @@ public:
void dump(DebugStream &out);
- QString sanityCheckFunctionNames(const QList<CompiledFunctionOrExpression> &allFunctions, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
+ QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
QString appendSignal(Signal *signal);
QString appendProperty(QmlProperty *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
@@ -228,6 +276,9 @@ public:
QString appendBinding(Binding *b, bool isListBinding);
Binding *findBinding(quint32 nameIndex) const;
+ PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
+ FixedPoolArray<int> *runtimeFunctionIndices;
+
private:
PoolList<QmlProperty> *properties;
PoolList<Signal> *qmlSignals;
@@ -259,7 +310,6 @@ struct ParsedQML
QQmlJS::AST::UiProgram *program;
int indexOfRootObject;
QList<QmlObject*> objects;
- QList<CompiledFunctionOrExpression> functions;
QV4::Compiler::JSUnitGenerator jsGenerator;
QV4::CompiledData::TypeReferenceMap typeReferences;
@@ -350,7 +400,6 @@ public:
QList<QV4::CompiledData::Import*> _imports;
QList<Pragma*> _pragmas;
QList<QmlObject*> _objects;
- QList<CompiledFunctionOrExpression> _functions;
QV4::CompiledData::TypeReferenceMap _typeReferences;
@@ -370,11 +419,11 @@ struct Q_QML_EXPORT QmlUnitGenerator
{
}
- QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices);
+ QV4::CompiledData::QmlUnit *generate(ParsedQML &output);
private:
typedef bool (Binding::*BindingFilter)() const;
- char *writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const;
+ char *writeBindings(char *bindingPtr, QmlObject *o, BindingFilter filter) const;
int getStringId(const QString &str) const;
@@ -430,7 +479,8 @@ private:
struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
{
JSCodeGen(const QString &fileName, const QString &sourceCode, IR::Module *jsModule,
- QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports);
+ QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
+ const QStringList &stringPool);
struct IdMapping
{
@@ -457,6 +507,7 @@ private:
QQmlJS::Engine *jsEngine; // needed for memory pool
QQmlJS::AST::UiProgram *qmlRoot;
QQmlTypeNameCache *imports;
+ const QStringList &stringPool;
bool _disableAcceleratedLookups;
ObjectIdMapping _idObjects;
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 71fc4c5d6a..a1085b1388 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -192,13 +192,11 @@ bool QQmlTypeCompiler::compile()
}
// Compile JS binding expressions and signal handlers
-
- JSCodeGen jsCodeGen(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache);
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
- QList<QQmlError> jsErrors = jsCodeGen.errors();
- if (!jsErrors.isEmpty()) {
- errors << jsErrors;
- return false;
+ {
+ QtQml::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache, parsedQML->jsGenerator.strings);
+ QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
+ if (!jsCodeGen.generateCodeForComponents())
+ return false;
}
QV4::ExecutionEngine *v4 = engine->v4engine();
@@ -210,7 +208,7 @@ bool QQmlTypeCompiler::compile()
// Generate QML compiled type data structures
QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML, runtimeFunctionIndices);
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML);
if (jsUnit) {
Q_ASSERT(!jsUnit->data);
@@ -240,7 +238,7 @@ bool QQmlTypeCompiler::compile()
}
// Sanity check property bindings
- QQmlPropertyValidator validator(this, runtimeFunctionIndices);
+ QQmlPropertyValidator validator(this);
if (!validator.validate())
return false;
@@ -355,11 +353,6 @@ QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
return parsedQML->jsParserEngine.pool();
}
-const QList<CompiledFunctionOrExpression> &QQmlTypeCompiler::functions() const
-{
- return parsedQML->functions;
-}
-
void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings)
{
compiledData->customParserBindings = bindings;
@@ -1384,7 +1377,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
, qmlUnit(typeCompiler->qmlUnit())
@@ -1392,7 +1385,6 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, con
, propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, customParserData(typeCompiler->customParserData())
- , runtimeFunctionIndices(runtimeFunctionIndices)
{
}
@@ -1409,18 +1401,20 @@ const QQmlImports &QQmlPropertyValidator::imports() const
return *compiler->imports();
}
-QQmlJS::AST::Node *QQmlPropertyValidator::astForBinding(int scriptIndex) const
+QQmlJS::AST::Node *QQmlPropertyValidator::astForBinding(int objectIndex, int scriptIndex) const
{
+ const QtQml::QmlObject *obj = compiler->qmlObjects()->at(objectIndex);
// ####
- int reverseIndex = runtimeFunctionIndices.indexOf(scriptIndex);
+ int reverseIndex = obj->runtimeFunctionIndices->indexOf(scriptIndex);
if (reverseIndex == -1)
return 0;
- return compiler->functions().value(reverseIndex).node;
+ QtQml::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(reverseIndex);
+ return foe ? foe->node : 0;
}
QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *)
{
- int id = customParserBindings.count();
+ const int id = customParserBindings.count();
customParserBindings.append(binding->value.compiledScriptIndex);
return id;
}
@@ -2026,4 +2020,108 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
return true;
}
+QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QtQml::JSCodeGen *v4CodeGen)
+ : QQmlCompilePass(typeCompiler)
+ , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
+ , resolvedTypes(*typeCompiler->resolvedTypes())
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , propertyCaches(typeCompiler->propertyCaches())
+ , v4CodeGen(v4CodeGen)
+{
+}
+
+bool QQmlJSCodeGenerator::generateCodeForComponents()
+{
+ const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent();
+ for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd();
+ component != end; ++component) {
+ if (!compileComponent(component.key(), component.value()))
+ return false;
+ }
+
+ return compileComponent(compiler->rootObjectIndex(), *compiler->objectIndexToIdForRoot());
+}
+
+bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId)
+{
+ if (isComponent(contextObject)) {
+ const QtQml::QmlObject *component = qmlObjects.at(contextObject);
+ Q_ASSERT(component->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = component->firstBinding();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ contextObject = componentBinding->value.objectIndex;
+ }
+
+ JSCodeGen::ObjectIdMapping idMapping;
+ if (!objectIndexToId.isEmpty()) {
+ idMapping.reserve(objectIndexToId.count());
+
+ for (QHash<int, int>::ConstIterator idIt = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
+ idIt != end; ++idIt) {
+
+ const int objectIndex = idIt.key();
+ JSCodeGen::IdMapping m;
+ m.name = stringAt(qmlObjects.at(objectIndex)->idIndex);
+ m.idIndex = idIt.value();
+ m.type = propertyCaches.at(objectIndex);
+ idMapping << m;
+ }
+
+ v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject));
+ }
+
+ if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
+ return false;
+
+ return true;
+}
+
+bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
+{
+ if (isComponent(objectIndex))
+ return true;
+
+ QtQml::QmlObject *object = qmlObjects.at(objectIndex);
+ if (object->functionsAndExpressions->count > 0) {
+ bool haveCustomParser = false;
+ QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(object->inheritedTypeNameIndex);
+ if (objectType && objectType->type)
+ haveCustomParser = objectType->type->customParser() != 0;
+
+ QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex);
+ v4CodeGen->beginObjectScope(scopeObject);
+
+ QList<QtQml::CompiledFunctionOrExpression> functionsToCompile;
+ for (QtQml::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
+ if (haveCustomParser)
+ foe->disableAcceleratedLookups = true;
+ functionsToCompile << *foe;
+ }
+ const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ QList<QQmlError> jsErrors = v4CodeGen->errors();
+ if (!jsErrors.isEmpty()) {
+ foreach (const QQmlError &e, jsErrors)
+ compiler->recordError(e);
+ return false;
+ }
+
+ QQmlJS::MemoryPool *pool = compiler->memoryPool();
+ object->runtimeFunctionIndices = pool->New<QtQml::FixedPoolArray<int> >();
+ object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
+ }
+
+ for (const QtQml::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ if (binding->type < QV4::CompiledData::Binding::Type_Object)
+ continue;
+
+ int target = binding->value.objectIndex;
+ int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
+
+ if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
+ return false;
+ }
+
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 3ef3bbf55f..71ae77ac5c 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -94,7 +94,6 @@ public:
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
QHash<int, QByteArray> *customParserData();
QQmlJS::MemoryPool *memoryPool();
- const QList<CompiledFunctionOrExpression> &functions() const;
void setCustomParserBindings(const QVector<int> &bindings);
private:
@@ -216,13 +215,13 @@ class QQmlPropertyValidator : public QQmlCompilePass, public QQmlCustomParserCom
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices);
+ QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler);
bool validate();
// Re-implemented for QQmlCustomParser
virtual const QQmlImports &imports() const;
- virtual QQmlJS::AST::Node *astForBinding(int scriptIndex) const;
+ virtual QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const;
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser);
private:
@@ -241,7 +240,27 @@ private:
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, QByteArray> *customParserData;
QVector<int> customParserBindings;
- const QVector<int> &runtimeFunctionIndices;
+};
+
+// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
+class QQmlJSCodeGenerator : public QQmlCompilePass
+{
+public:
+ QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QtQml::JSCodeGen *v4CodeGen);
+
+ bool generateCodeForComponents();
+
+private:
+ bool compileComponent(int componentRoot, const QHash<int, int> &objectIndexToId);
+ bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
+
+ bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
+
+ const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent;
+ const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
+ const QList<QtQml::QmlObject*> &qmlObjects;
+ const QVector<QQmlPropertyCache *> &propertyCaches;
+ QtQml::JSCodeGen * const v4CodeGen;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index b26b5530a3..3e2fc91cf5 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -3642,6 +3642,8 @@ bool QQmlCompiler::completeComponentBuild()
const QQmlScript::Parser &parser = unit->parser();
QQmlJS::Engine *jsEngine = parser.jsEngine();
QQmlJS::MemoryPool *pool = jsEngine->pool();
+ QStringList stringPool;
+ stringPool.append(QString());
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
@@ -3659,7 +3661,9 @@ bool QQmlCompiler::completeComponentBuild()
ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object];
QtQml::CompiledFunctionOrExpression f;
f.node = node;
- f.name = binding.property->name().toString().prepend(QStringLiteral("expression for "));
+ QString name = binding.property->name().toString().prepend(QStringLiteral("expression for "));
+ stringPool.append(name);
+ f.nameIndex = stringPool.count() - 1;
f.disableAcceleratedLookups = binding.disableLookupAcceleration;
cd->functionsToCompile.append(f);
binding.compiledIndex = cd->functionsToCompile.count() - 1;
@@ -3672,7 +3676,7 @@ bool QQmlCompiler::completeComponentBuild()
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
+ JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache, stringPool);
JSCodeGen::ObjectIdMapping idMapping;
if (compileState->ids.count() > 0) {
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index fc14fae275..f661317794 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -333,9 +333,9 @@ QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledD
return compiler->bindingIdentifier(binding, this);
}
-QQmlJS::AST::Node *QQmlCustomParser::astForBinding(int scriptIndex) const
+QQmlJS::AST::Node *QQmlCustomParser::astForBinding(int objectIndex, int scriptIndex) const
{
- return compiler->astForBinding(scriptIndex);
+ return compiler->astForBinding(objectIndex, scriptIndex);
}
struct StaticQtMetaObject : public QObject
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index d06a8c1551..96810c2f40 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -119,7 +119,7 @@ struct QQmlCustomParserCompilerBackend
virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&, QQmlCustomParser *) { return QQmlBinding::Invalid; }
virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; }
- virtual QQmlJS::AST::Node *astForBinding(int) const { return 0; }
+ virtual QQmlJS::AST::Node *astForBinding(int, int) const { return 0; }
};
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
@@ -162,7 +162,7 @@ protected:
QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&);
QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding);
- QQmlJS::AST::Node *astForBinding(int scriptIndex) const;
+ QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const;
private:
QList<QQmlError> exceptions;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index eed76ee09e..0dc1c2c25c 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2387,8 +2387,9 @@ bool QQmlListModelParser::compileProperty(const QQmlCustomParserProperty &prop,
bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data)
{
+ const quint32 targetObjectIndex = binding->value.objectIndex;
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Object *target = qmlUnit->objectAt(targetObjectIndex);
QString objName = qmlUnit->header.stringAt(target->inheritedTypeNameIndex);
if (objName != listElementTypeName) {
const QMetaObject *mo = resolveType(objName);
@@ -2465,7 +2466,7 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
int v = evaluateEnum(script, &ok);
if (!ok) {
using namespace QQmlJS;
- AST::Node *node = astForBinding(binding->value.compiledScriptIndex);
+ AST::Node *node = astForBinding(targetObjectIndex, binding->value.compiledScriptIndex);
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node))
node = stmt->expression;
AST::StringLiteral *literal = 0;