From: Simon Hausmann Date: Tue, 25 Feb 2014 15:36:41 +0000 (+0100) Subject: [new compiler] Compile functions and bindings in appropriate scopes X-Git-Tag: upstream/5.2.90+alpha~106 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=963875db263e4d1a04e03c4bb4fc20542bc8c21e;p=platform%2Fupstream%2Fqtdeclarative.git [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 --- diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 35f303c9f..56e5d7183 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 >(); bindings = pool->New >(); functions = pool->New >(); + functionsAndExpressions = pool->New >(); + runtimeFunctionIndices = 0; declarationsOverride = 0; } @@ -91,14 +93,13 @@ void QmlObject::dump(DebugStream &out) out << "}" << endl; } -QString QmlObject::sanityCheckFunctionNames(const QList &allFunctions, const QSet &illegalNames, QQmlJS::AST::SourceLocation *errorLocation) +QString QmlObject::sanityCheckFunctionNames(const QSet &illegalNames, QQmlJS::AST::SourceLocation *errorLocation) { QSet functionNames; for (Function *f = functions->first; f; f = f->next) { - QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast(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 QListname.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(node->sourceElement)) { - _functions << funDecl; + CompiledFunctionOrExpression *foe = New(); + foe->node = funDecl; + foe->nameIndex = registerString(funDecl->name.toString()); + foe->disableAcceleratedLookups = false; + const int index = _object->functionsAndExpressions->append(foe); + Function *f = New(); 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(); + 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 &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(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(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 &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(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 JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListname.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(parsedQML->functions[binding->value.compiledScriptIndex].node); + CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex); + QQmlJS::AST::Statement *statement = static_cast(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 7f27bded2..304df224c 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 +class FixedPoolArray +{ + T *data; + int count; +public: + + void init(QQmlJS::MemoryPool *pool, const QVector &vector) + { + count = vector.count(); + data = reinterpret_cast(pool->allocate(count * sizeof(T))); + + if (QTypeInfo::isComplex) { + for (int i = 0; i < count; ++i) + new (data + i) T(vector.at(i)); + } else { + memcpy(data, static_cast(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 &allFunctions, const QSet &illegalNames, QQmlJS::AST::SourceLocation *errorLocation); + QString sanityCheckFunctionNames(const QSet &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 *functionsAndExpressions; + FixedPoolArray *runtimeFunctionIndices; + private: PoolList *properties; PoolList *qmlSignals; @@ -259,7 +310,6 @@ struct ParsedQML QQmlJS::AST::UiProgram *program; int indexOfRootObject; QList objects; - QList functions; QV4::Compiler::JSUnitGenerator jsGenerator; QV4::CompiledData::TypeReferenceMap typeReferences; @@ -350,7 +400,6 @@ public: QList _imports; QList _pragmas; QList _objects; - QList _functions; QV4::CompiledData::TypeReferenceMap _typeReferences; @@ -370,11 +419,11 @@ struct Q_QML_EXPORT QmlUnitGenerator { } - QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector &runtimeFunctionIndices); + QV4::CompiledData::QmlUnit *generate(ParsedQML &output); private: typedef bool (Binding::*BindingFilter)() const; - char *writeBindings(char *bindingPtr, QmlObject *o, const QVector &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 71fc4c5d6..a1085b138 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 runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions); - QList 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 &QQmlTypeCompiler::functions() const -{ - return parsedQML->functions; -} - void QQmlTypeCompiler::setCustomParserBindings(const QVector &bindings) { compiledData->customParserBindings = bindings; @@ -1384,7 +1377,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() } -QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector &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 > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent(); + for (QHash >::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 &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::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 functionsToCompile; + for (QtQml::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) { + if (haveCustomParser) + foe->disableAcceleratedLookups = true; + functionsToCompile << *foe; + } + const QVector runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile); + QList 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 >(); + 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 3ef3bbf55..71ae77ac5 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -94,7 +94,6 @@ public: QHash > *objectIndexToIdPerComponent(); QHash *customParserData(); QQmlJS::MemoryPool *memoryPool(); - const QList &functions() const; void setCustomParserBindings(const QVector &bindings); private: @@ -216,13 +215,13 @@ class QQmlPropertyValidator : public QQmlCompilePass, public QQmlCustomParserCom { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) public: - QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector &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 > objectIndexToIdPerComponent; QHash *customParserData; QVector customParserBindings; - const QVector &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 &objectIndexToId); + bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex); + + bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } + + const QHash > &objectIndexToIdPerComponent; + const QHash &resolvedTypes; + const QList &qmlObjects; + const QVector &propertyCaches; + QtQml::JSCodeGen * const v4CodeGen; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index b26b5530a..3e2fc91cf 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 fc14fae27..f66131779 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 d06a8c155..96810c2f4 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 exceptions; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index eed76ee09..0dc1c2c25 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 &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(node)) node = stmt->expression; AST::StringLiteral *literal = 0;