[new compiler] Compile functions and bindings in appropriate scopes
authorSimon Hausmann <simon.hausmann@digia.com>
Tue, 25 Feb 2014 15:36:41 +0000 (16:36 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Sun, 2 Mar 2014 13:48:43 +0000 (14:48 +0100)
This enables accelerated property access also for this code path.

Change-Id: Iafb177b1fe7878e6c54cfb258f2e8d8ea32aa59e
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qqmlcodegenerator.cpp
src/qml/compiler/qqmlcodegenerator_p.h
src/qml/compiler/qqmltypecompiler.cpp
src/qml/compiler/qqmltypecompiler_p.h
src/qml/qml/qqmlcompiler.cpp
src/qml/qml/qqmlcustomparser.cpp
src/qml/qml/qqmlcustomparser_p.h
src/qml/types/qqmllistmodel.cpp

index 35f303c9fc333a855f715634675d81f74333de4d..56e5d7183dbbbd3b3e8ba87efd89e004463edf77 100644 (file)
@@ -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;
index 7f27bded20c8df91105ed5e1418804e3115e5056..304df224c0b39847fe26dd1780687093f230749f 100644 (file)
@@ -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;
index 71fc4c5d6a5255c7b9c51d41291be60d2d9c5bfe..a1085b1388b54ba9c09df194c1bbffe1aee67d45 100644 (file)
@@ -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
index 3ef3bbf55fdb19dee911e1e0854307177b4383c3..71ae77ac5c6741fcfee49de981e5a4dd0819c3e6 100644 (file)
@@ -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
index b26b5530a324846c58bb4a4c6be5c61dd86f5a51..3e2fc91cf52729e207a42439d439a7dcab93be6f 100644 (file)
@@ -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) {
index fc14fae2753c23bf31914f8ecc9628b6f371ae1e..f661317794eb7cf01757f6aefde61da63919b6d0 100644 (file)
@@ -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
index d06a8c1551a0df3b52245af7ce27f2b080b166c2..96810c2f40510ae52eabed9452722d2acc3fb8ba 100644 (file)
@@ -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;
index eed76ee09e1281ac3c6149e67f882c4006f8f22d..0dc1c2c25ccdcab4414fc31b5af9a14f7713292b 100644 (file)
@@ -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;