From a9bef84675f6b67bb88a2bb99e45aba889795251 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 12 Dec 2013 15:20:09 +0100 Subject: [new compiler] Cleanups Move the code that calls the main compilation passes into a separate QQmlTypeCompiler class, away from the QQmlTypeLoader. Change-Id: Ia2f33a074d7fe7d9a092ff94d1e6cfc961ad5bdb Reviewed-by: Lars Knoll --- src/qml/compiler/compiler.pri | 6 +- src/qml/compiler/qqmltypecompiler.cpp | 220 ++++++++++++++++++++++++++++++++++ src/qml/compiler/qqmltypecompiler_p.h | 75 ++++++++++++ src/qml/qml/qqmltypeloader.cpp | 175 +-------------------------- src/qml/qml/qqmltypeloader_p.h | 5 + 5 files changed, 308 insertions(+), 173 deletions(-) create mode 100644 src/qml/compiler/qqmltypecompiler.cpp create mode 100644 src/qml/compiler/qqmltypecompiler_p.h (limited to 'src') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index df4f5e8dc3..b2569f9111 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -15,7 +15,8 @@ HEADERS += \ $$PWD/qv4ssa_p.h \ $$PWD/qv4regalloc_p.h \ $$PWD/qqmlcodegenerator_p.h \ - $$PWD/qv4isel_masm_p.h + $$PWD/qv4isel_masm_p.h \ + $$PWD/qqmltypecompiler_p.h SOURCES += \ $$PWD/qv4compileddata.cpp \ @@ -28,6 +29,7 @@ SOURCES += \ $$PWD/qv4ssa.cpp \ $$PWD/qv4regalloc.cpp \ $$PWD/qqmlcodegenerator.cpp \ - $$PWD/qv4isel_masm.cpp + $$PWD/qv4isel_masm.cpp \ + $$PWD/qqmltypecompiler.cpp include(../../3rdparty/masm/masm.pri) diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp new file mode 100644 index 0000000000..7ff5570f14 --- /dev/null +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmltypecompiler_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QtQml::ParsedQML *parsedQML) + : engine(engine) + , compiledData(compiledData) + , typeData(typeData) + , parsedQML(parsedQML) +{ +} + +bool QQmlTypeCompiler::compile() +{ + compiledData->importCache = new QQmlTypeNameCache; + + foreach (const QString &ns, typeData->namespaces()) + compiledData->importCache->add(ns); + + // Add any Composite Singletons that were used to the import cache + foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons()) + compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); + + typeData->imports().populateCache(compiledData->importCache); + compiledData->importCache->addref(); + + const QHash &resolvedTypes = typeData->resolvedTypeRefs(); + for (QHash::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); + resolvedType != end; ++resolvedType) { + QQmlCompiledData::TypeReference ref; + if (resolvedType->typeData) { + ref.component = resolvedType->typeData->compiledData(); + ref.component->addref(); + } else { + ref.type = resolvedType->type; + Q_ASSERT(ref.type); + } + ref.majorVersion = resolvedType->majorVersion; + ref.minorVersion = resolvedType->minorVersion; + compiledData->resolvedTypes.insert(resolvedType.key(), ref); + } + + // Build property caches and VME meta object data + + const int objectCount = parsedQML->objects.count(); + compiledData->datas.reserve(objectCount); + compiledData->propertyCaches.reserve(objectCount); + + QQmlPropertyCacheCreator propertyCacheBuilder(engine, + parsedQML->jsGenerator.strings, compiledData->url, + &typeData->imports(), &compiledData->resolvedTypes); + + for (int i = 0; i < objectCount; ++i) { + const QtQml::QmlObject *obj = parsedQML->objects.at(i); + + QByteArray vmeMetaObjectData; + QQmlPropertyCache *propertyCache = 0; + + // If the object has no type, then it's probably a nested object definition as part + // of a group property. + const bool objectHasType = !propertyCacheBuilder.stringAt(obj->inheritedTypeNameIndex).isEmpty(); + if (objectHasType) { + if (!propertyCacheBuilder.create(obj, &propertyCache, &vmeMetaObjectData)) { + errors << propertyCacheBuilder.errors; + return false; + } + } + + compiledData->datas << vmeMetaObjectData; + if (propertyCache) + propertyCache->addref(); + compiledData->propertyCaches << propertyCache; + + if (i == parsedQML->indexOfRootObject) { + Q_ASSERT(propertyCache); + compiledData->rootPropertyCache = propertyCache; + propertyCache->addref(); + } + } + + { + SignalHandlerConverter converter(engine, parsedQML, compiledData); + if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations()) { + errors << converter.errors; + return false; + } + } + + // Collect imported scripts + const QList &scripts = typeData->resolvedScripts(); + compiledData->scripts.reserve(scripts.count()); + for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) { + const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex); + + QString qualifier = script.qualifier; + QString enclosingNamespace; + + const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); + if (lastDotIndex != -1) { + enclosingNamespace = qualifier.left(lastDotIndex); + qualifier = qualifier.mid(lastDotIndex+1); + } + + compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace); + QQmlScriptData *scriptData = script.script->scriptData(); + scriptData->addref(); + compiledData->scripts << scriptData; + } + + // 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); + + QV4::ExecutionEngine *v4 = engine->v4engine(); + + QScopedPointer isel(v4->iselFactory->create(engine, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator)); + isel->setUseFastLookups(false); + QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false); + + // Generate QML compiled type data structures + + QmlUnitGenerator qmlGenerator; + QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML, runtimeFunctionIndices); + + if (jsUnit) { + Q_ASSERT(!jsUnit->data); + jsUnit->ownsData = false; + jsUnit->data = &qmlUnit->header; + } + + compiledData->compilationUnit = jsUnit; + if (compiledData->compilationUnit) + compiledData->compilationUnit->ref(); + compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData + + // Resolve component boundaries and aliases + + { + // Scan for components, determine their scopes and resolve aliases within the scope. + QQmlComponentAndAliasResolver resolver(compiledData->url, compiledData->qmlUnit, compiledData->resolvedTypes, compiledData->propertyCaches, + &compiledData->datas, &compiledData->objectIndexToIdForRoot, &compiledData->objectIndexToIdPerComponent); + if (!resolver.resolve()) { + errors << resolver.errors; + return false; + } + } + + // Add to type registry of composites + if (compiledData->isCompositeType()) + engine->registerInternalCompositeType(compiledData); + else { + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject); + QQmlCompiledData::TypeReference typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex); + if (typeRef.component) { + compiledData->metaTypeId = typeRef.component->metaTypeId; + compiledData->listMetaTypeId = typeRef.component->listMetaTypeId; + } else { + compiledData->metaTypeId = typeRef.type->typeId(); + compiledData->listMetaTypeId = typeRef.type->qListTypeId(); + } + } + + // Sanity check property bindings + QQmlPropertyValidator validator(compiledData->url, compiledData->qmlUnit, compiledData->resolvedTypes, + compiledData->propertyCaches, compiledData->objectIndexToIdPerComponent, + &compiledData->customParserData); + if (!validator.validate()) { + errors << validator.errors; + return false; + } + + return errors.isEmpty(); +} + +QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h new file mode 100644 index 0000000000..9592e5d611 --- /dev/null +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQMLTYPECOMPILER_P_H +#define QQMLTYPECOMPILER_P_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlEnginePrivate; +class QQmlCompiledData; +class QQmlError; +class QQmlTypeData; + +namespace QtQml { +struct ParsedQML; +} + +struct QQmlTypeCompiler +{ + QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QtQml::ParsedQML *parsedQML); + + bool compile(); + + QList errors; + +private: + QQmlEnginePrivate *engine; + QQmlCompiledData *compiledData; + QQmlTypeData *typeData; + QtQml::ParsedQML *parsedQML; +}; + +QT_END_NAMESPACE + +#endif // QQMLTYPECOMPILER_P_H diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 5b6d91475b..9e23b0b1a5 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -2306,177 +2307,9 @@ void QQmlTypeData::compile() QQmlCompilingProfiler prof(m_compiledData->name); if (m_useNewCompiler) { - m_compiledData->importCache = new QQmlTypeNameCache; - - foreach (const QString &ns, m_namespaces) - m_compiledData->importCache->add(ns); - - // Add any Composite Singletons that were used to the import cache - for (int i = 0; i < compositeSingletons().count(); ++i) { - m_compiledData->importCache->add(compositeSingletons().at(i).type->qmlTypeName(), - compositeSingletons().at(i).type->sourceUrl(), compositeSingletons().at(i).prefix); - } - - m_imports.populateCache(m_compiledData->importCache); - m_compiledData->importCache->addref(); - - QQmlEngine *engine = typeLoader()->engine(); - QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - - for (QHash::ConstIterator resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); - resolvedType != end; ++resolvedType) { - QQmlCompiledData::TypeReference ref; - if (resolvedType->typeData) { - ref.component = resolvedType->typeData->compiledData(); - ref.component->addref(); - } else { - ref.type = resolvedType->type; - Q_ASSERT(ref.type); - } - ref.majorVersion = resolvedType->majorVersion; - ref.minorVersion = resolvedType->minorVersion; - m_compiledData->resolvedTypes.insert(resolvedType.key(), ref); - } - - // Build property caches and VME meta object data - - const int objectCount = parsedQML->objects.count(); - m_compiledData->datas.reserve(objectCount); - m_compiledData->propertyCaches.reserve(objectCount); - - QQmlPropertyCacheCreator propertyCacheBuilder(enginePrivate, - parsedQML->jsGenerator.strings, m_compiledData->url, - &m_imports, &m_compiledData->resolvedTypes); - - for (int i = 0; i < objectCount; ++i) { - const QtQml::QmlObject *obj = parsedQML->objects.at(i); - - QByteArray vmeMetaObjectData; - QQmlPropertyCache *propertyCache = 0; - - // If the object has no type, then it's probably a nested object definition as part - // of a group property. - const bool objectHasType = !propertyCacheBuilder.stringAt(obj->inheritedTypeNameIndex).isEmpty(); - if (objectHasType) { - if (!propertyCacheBuilder.create(obj, &propertyCache, &vmeMetaObjectData)) { - setError(propertyCacheBuilder.errors); - m_compiledData->release(); - m_compiledData = 0; - return; - } - } - - m_compiledData->datas << vmeMetaObjectData; - if (propertyCache) - propertyCache->addref(); - m_compiledData->propertyCaches << propertyCache; - - if (i == parsedQML->indexOfRootObject) { - Q_ASSERT(propertyCache); - m_compiledData->rootPropertyCache = propertyCache; - propertyCache->addref(); - } - } - - { - SignalHandlerConverter converter(QQmlEnginePrivate::get(engine), - parsedQML.data(), - m_compiledData); - if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations()) { - setError(converter.errors); - m_compiledData->release(); - m_compiledData = 0; - return; - } - } - - // Collect imported scripts - m_compiledData->scripts.reserve(m_scripts.count()); - for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) { - const ScriptReference &script = m_scripts.at(scriptIndex); - - QString qualifier = script.qualifier; - QString enclosingNamespace; - - const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); - if (lastDotIndex != -1) { - enclosingNamespace = qualifier.left(lastDotIndex); - qualifier = qualifier.mid(lastDotIndex+1); - } - - m_compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace); - QQmlScriptData *scriptData = script.script->scriptData(); - scriptData->addref(); - m_compiledData->scripts << scriptData; - } - - // Compile JS binding expressions and signal handlers - - JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache); - const QVector runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions); - - QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); - - QScopedPointer isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator)); - isel->setUseFastLookups(false); - QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false); - - // Generate QML compiled type data structures - - QmlUnitGenerator qmlGenerator; - QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML.data(), runtimeFunctionIndices); - - if (jsUnit) { - Q_ASSERT(!jsUnit->data); - jsUnit->ownsData = false; - jsUnit->data = &qmlUnit->header; - } - - m_compiledData->compilationUnit = jsUnit; - if (m_compiledData->compilationUnit) - m_compiledData->compilationUnit->ref(); - m_compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData - - QList errors; - - // Resolve component boundaries and aliases - - { - // Scan for components, determine their scopes and resolve aliases within the scope. - QQmlComponentAndAliasResolver resolver(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, m_compiledData->propertyCaches, - &m_compiledData->datas, &m_compiledData->objectIndexToIdForRoot, &m_compiledData->objectIndexToIdPerComponent); - if (!resolver.resolve()) - errors << resolver.errors; - } - - if (errors.isEmpty()) { - // Add to type registry of composites - if (m_compiledData->isCompositeType()) - QQmlEnginePrivate::get(engine)->registerInternalCompositeType(m_compiledData); - else { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject); - QQmlCompiledData::TypeReference typeRef = m_compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex); - if (typeRef.component) { - m_compiledData->metaTypeId = typeRef.component->metaTypeId; - m_compiledData->listMetaTypeId = typeRef.component->listMetaTypeId; - } else { - m_compiledData->metaTypeId = typeRef.type->typeId(); - m_compiledData->listMetaTypeId = typeRef.type->qListTypeId(); - } - } - } - - // Sanity check property bindings - if (errors.isEmpty()) { - QQmlPropertyValidator validator(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, - m_compiledData->propertyCaches, m_compiledData->objectIndexToIdPerComponent, - &m_compiledData->customParserData); - if (!validator.validate()) - errors << validator.errors; - } - - if (!errors.isEmpty()) { - setError(errors); + QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, parsedQML.data()); + if (!compiler.compile()) { + setError(compiler.errors); m_compiledData->release(); m_compiledData = 0; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index b93cf2942d..a022162a7c 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -425,7 +425,12 @@ public: const QQmlScript::Parser &parser() const; + // old compiler: const QList &resolvedTypes() const; + // new compiler: + const QHash &resolvedTypeRefs() const { return m_resolvedTypes; } + // --- + const QList &resolvedScripts() const; const QSet &namespaces() const; const QList &compositeSingletons() const; -- cgit v1.2.3