aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-08-06 16:41:28 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-08 09:00:05 +0200
commit5b456c8da4462f9e11fa4da78a9e6ea86423a1e8 (patch)
treec8a24054a711d0ca4aed52ddcc480fcd25b32c91
parentdea991ec5b6e1e8546dfd3695c12425ee27d2ef3 (diff)
Beginning of a new qml parser
The goal is to parse QML and JavaScript binding expressions/functions in one go and generate data structures that allow for the parsing to happen in a thread and the instantiation of the object tree in another thread, just reading from the generated data structures. This will replace qqmlcompiler and the VME. This new way of loading QML is currently hidden behind the QML_NEW_COMPILER=1 environment variable. There's lots of work left to fill in the gaps in object construction, Component support, Component.onComplete, error messages, etc. etc. Change-Id: I5e40643cff169f469f0b6ce151584ffee5ca5e90 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/compiler.pri6
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp776
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h262
-rw-r--r--src/qml/compiler/qv4codegen.cpp10
-rw-r--r--src/qml/compiler/qv4codegen_p.h4
-rw-r--r--src/qml/compiler/qv4compileddata_p.h141
-rw-r--r--src/qml/compiler/qv4compiler.cpp17
-rw-r--r--src/qml/compiler/qv4compiler_p.h11
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp2
-rw-r--r--src/qml/compiler/qv4isel_p.cpp9
-rw-r--r--src/qml/compiler/qv4isel_p.h2
-rw-r--r--src/qml/compiler/qv4jsir.cpp4
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4script.cpp79
-rw-r--r--src/qml/jsruntime/qv4script_p.h14
-rw-r--r--src/qml/qml/qml.pri6
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h5
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp6
-rw-r--r--src/qml/qml/qqmlcompiler_p.h12
-rw-r--r--src/qml/qml/qqmlcomponent.cpp26
-rw-r--r--src/qml/qml/qqmlcomponent_p.h16
-rw-r--r--src/qml/qml/qqmlengine.cpp2
-rw-r--r--src/qml/qml/qqmlengine_p.h1
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp686
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h97
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h5
-rw-r--r--src/qml/qml/qqmltypeloader.cpp79
-rw-r--r--src/qml/qml/qqmltypeloader_p.h6
29 files changed, 2171 insertions, 116 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index ef1a0cb4d0..3a1af30b88 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -13,7 +13,8 @@ HEADERS += \
$$PWD/qv4isel_moth_p.h \
$$PWD/qv4isel_util_p.h \
$$PWD/qv4ssa_p.h \
- $$PWD/qv4regalloc_p.h
+ $$PWD/qv4regalloc_p.h \
+ $$PWD/qqmlcodegenerator_p.h
SOURCES += \
$$PWD/qv4compileddata.cpp \
@@ -24,7 +25,8 @@ SOURCES += \
$$PWD/qv4isel_p.cpp \
$$PWD/qv4jsir.cpp \
$$PWD/qv4ssa.cpp \
- $$PWD/qv4regalloc.cpp
+ $$PWD/qv4regalloc.cpp \
+ $$PWD/qqmlcodegenerator.cpp
contains(DEFINES, V4_ENABLE_JIT) {
HEADERS += $$PWD/qv4isel_masm_p.h
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
new file mode 100644
index 0000000000..c2ad55dda3
--- /dev/null
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -0,0 +1,776 @@
+/****************************************************************************
+**
+** 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 "qqmlcodegenerator_p.h"
+
+#include <private/qv4compileddata_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljslexer_p.h>
+#include <QCoreApplication>
+
+QT_USE_NAMESPACE
+
+using namespace QtQml;
+
+void QmlObject::dump(DebugStream &out)
+{
+ out << inheritedTypeNameIndex << " {" << endl;
+ out.indent++;
+
+ out.indent--;
+ out << "}" << endl;
+}
+
+QQmlCodeGenerator::QQmlCodeGenerator()
+ : _object(0)
+ , jsGenerator(0)
+{
+}
+
+bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output)
+{
+ AST::UiProgram *program = 0;
+ {
+ QQmlJS::Lexer lexer(&output->jsParserEngine);
+ lexer.setCode(code, /*line = */ 1);
+
+ QQmlJS::Parser parser(&output->jsParserEngine);
+
+ if (! parser.parse() || !parser.diagnosticMessages().isEmpty()) {
+
+ // Extract errors from the parser
+ foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) {
+
+ if (m.isWarning()) {
+ qWarning("%s:%d : %s", qPrintable(urlString), m.loc.startLine, qPrintable(m.message));
+ continue;
+ }
+
+ QQmlError error;
+ error.setUrl(url);
+ error.setDescription(m.message);
+ error.setLine(m.loc.startLine);
+ error.setColumn(m.loc.startColumn);
+ errors << error;
+ }
+ return false;
+ }
+ program = parser.ast();
+ Q_ASSERT(program);
+ }
+
+ output->code = code;
+
+ qSwap(_imports, output->imports);
+ qSwap(_objects, output->objects);
+ qSwap(_functions, output->functions);
+ this->pool = output->jsParserEngine.pool();
+ this->jsGenerator = &output->jsGenerator;
+
+ sourceCode = code;
+
+ accept(program->imports);
+
+ if (program->members->next) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser", "Unexpected object definition"));
+ AST::SourceLocation loc = program->members->next->firstSourceLocation();
+ error.setLine(loc.startLine);
+ error.setColumn(loc.startColumn);
+ errors << error;
+ return false;
+ }
+ AST::UiObjectDefinition *rootObject = AST::cast<AST::UiObjectDefinition*>(program->members->member);
+ Q_ASSERT(rootObject);
+ output->indexOfRootObject = defineQMLObject(rootObject);
+ qSwap(_imports, output->imports);
+ qSwap(_objects, output->objects);
+ qSwap(_functions, output->functions);
+ return true;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiArrayMemberList *ast)
+{
+ return AST::Visitor::visit(ast);
+}
+
+bool QQmlCodeGenerator::visit(AST::UiProgram *)
+{
+ Q_ASSERT(!"should not happen");
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node)
+{
+ int idx = defineQMLObject(node);
+ appendBinding(registerString(QString()), idx);
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiObjectBinding *node)
+{
+ int idx = defineQMLObject(node->qualifiedTypeNameId, node->initializer);
+ appendBinding(registerString(asString(node->qualifiedId)), idx);
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiScriptBinding *node)
+{
+ appendBinding(registerString(asString(node->qualifiedId)), node->statement);
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiArrayBinding*)
+{
+ return true;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiImportList *list)
+{
+ return AST::Visitor::visit(list);
+}
+
+bool QQmlCodeGenerator::visit(AST::UiObjectInitializer *ast)
+{
+ return AST::Visitor::visit(ast);
+}
+
+bool QQmlCodeGenerator::visit(AST::UiObjectMemberList *ast)
+{
+ return AST::Visitor::visit(ast);
+}
+
+bool QQmlCodeGenerator::visit(AST::UiParameterList *ast)
+{
+ return AST::Visitor::visit(ast);
+}
+
+bool QQmlCodeGenerator::visit(AST::UiQualifiedId *id)
+{
+ return AST::Visitor::visit(id);
+}
+
+void QQmlCodeGenerator::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer)
+{
+ QmlObject *obj = New<QmlObject>();
+ _objects.append(obj);
+ const int objectIndex = _objects.size() - 1;
+ qSwap(_object, obj);
+
+ _object->inheritedTypeNameIndex = registerString(asString(qualifiedTypeNameId));
+ _object->idIndex = registerString(QString());
+ _object->indexOfDefaultProperty = -1;
+ _object->properties = New<PoolList<QmlProperty> >();
+ _object->qmlSignals = New<PoolList<Signal> >();
+ _object->bindings = New<PoolList<Binding> >();
+ _object->functions = New<PoolList<Function> >();
+
+ accept(initializer);
+
+ qSwap(_object, obj);
+ return objectIndex;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiImport *node)
+{
+ QString uri;
+ QV4::CompiledData::Import *import = New<QV4::CompiledData::Import>();
+
+ if (!node->fileName.isNull()) {
+ uri = node->fileName.toString();
+
+ if (uri.endsWith(QLatin1String(".js"))) {
+ import->type = QV4::CompiledData::Import::ImportScript;
+ } else {
+ import->type = QV4::CompiledData::Import::ImportFile;
+ }
+ } else {
+ import->type = QV4::CompiledData::Import::ImportLibrary;
+ uri = asString(node->importUri);
+ }
+
+ import->qualifierIndex = registerString(QString());
+
+ // Qualifier
+ if (!node->importId.isNull()) {
+ QString qualifier = node->importId.toString();
+ if (!qualifier.at(0).isUpper()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier ID"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ errors << error;
+ return false;
+ }
+ if (qualifier == QLatin1String("Qt")) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Reserved name \"Qt\" cannot be used as an qualifier"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ errors << error;
+ return false;
+ }
+ import->qualifierIndex = registerString(qualifier);
+
+ // Check for script qualifier clashes
+ bool isScript = import->type == QV4::CompiledData::Import::ImportScript;
+ for (int ii = 0; ii < _imports.count(); ++ii) {
+ QV4::CompiledData::Import *other = _imports.at(ii);
+ bool otherIsScript = other->type == QV4::CompiledData::Import::ImportScript;
+
+ if ((isScript || otherIsScript) && qualifier == jsGenerator->strings.at(other->qualifierIndex)) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique."));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ errors << error;
+ return false;
+ }
+ }
+
+ } else if (import->type == QV4::CompiledData::Import::ImportScript) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Script import requires a qualifier"));
+ error.setLine(node->fileNameToken.startLine);
+ error.setColumn(node->fileNameToken.startColumn);
+ errors << error;
+ return false;
+ }
+
+ if (node->versionToken.isValid()) {
+ extractVersion(textRefAt(node->versionToken), &import->majorVersion, &import->minorVersion);
+ } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Library import requires a version"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ errors << error;
+ return false;
+ }
+
+ import->location.line = node->importIdToken.startLine;
+ import->location.column = node->importIdToken.startColumn;
+
+ import->uriIndex = registerString(uri);
+
+ _imports.append(import);
+
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
+{
+ static const struct TypeNameToType {
+ const char *name;
+ size_t nameLength;
+ QV4::CompiledData::Property::Type type;
+ } propTypeNameToTypes[] = {
+ { "int", strlen("int"), QV4::CompiledData::Property::Int },
+ { "bool", strlen("bool"), QV4::CompiledData::Property::Bool },
+ { "double", strlen("double"), QV4::CompiledData::Property::Real },
+ { "real", strlen("real"), QV4::CompiledData::Property::Real },
+ { "string", strlen("string"), QV4::CompiledData::Property::String },
+ { "url", strlen("url"), QV4::CompiledData::Property::Url },
+ { "color", strlen("color"), QV4::CompiledData::Property::Color },
+ // Internally QTime, QDate and QDateTime are all supported.
+ // To be more consistent with JavaScript we expose only
+ // QDateTime as it matches closely with the Date JS type.
+ // We also call it "date" to match.
+ // { "time", strlen("time"), Property::Time },
+ // { "date", strlen("date"), Property::Date },
+ { "date", strlen("date"), QV4::CompiledData::Property::DateTime },
+ { "rect", strlen("rect"), QV4::CompiledData::Property::Rect },
+ { "point", strlen("point"), QV4::CompiledData::Property::Point },
+ { "size", strlen("size"), QV4::CompiledData::Property::Size },
+ { "font", strlen("font"), QV4::CompiledData::Property::Font },
+ { "vector2d", strlen("vector2d"), QV4::CompiledData::Property::Vector2D },
+ { "vector3d", strlen("vector3d"), QV4::CompiledData::Property::Vector3D },
+ { "vector4d", strlen("vector4d"), QV4::CompiledData::Property::Vector4D },
+ { "quaternion", strlen("quaternion"), QV4::CompiledData::Property::Quaternion },
+ { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::Property::Matrix4x4 },
+ { "variant", strlen("variant"), QV4::CompiledData::Property::Variant },
+ { "var", strlen("var"), QV4::CompiledData::Property::Var }
+ };
+ static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+ sizeof(propTypeNameToTypes[0]);
+
+ if (node->type == AST::UiPublicMember::Signal) {
+ Signal *signal = New<Signal>();
+ signal->nameIndex = registerString(node->name.toString());
+ signal->parameters = New<PoolList<SignalParameter> >();
+
+ AST::UiParameterList *p = node->parameters;
+ while (p) {
+ const QStringRef &memberType = p->type;
+
+ if (memberType.isEmpty()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Expected parameter type"));
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ errors << error;
+ return false;
+ }
+
+ const TypeNameToType *type = 0;
+ for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
+ const TypeNameToType *t = propTypeNameToTypes + typeIndex;
+ if (t->nameLength == size_t(memberType.length()) &&
+ QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+ type = t;
+ break;
+ }
+ }
+
+ SignalParameter *param = New<SignalParameter>();
+
+ if (!type) {
+ if (memberType.at(0).isUpper()) {
+ // Must be a QML object type.
+ // Lazily determine type during compilation.
+ param->type = QV4::CompiledData::Property::Custom;
+ param->customTypeNameIndex = registerString(p->type.toString());
+ } else {
+ QQmlError error;
+ QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
+ errStr.append(memberType.toString());
+ error.setDescription(errStr);
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ errors << error;
+ return false;
+ }
+ } else {
+ // the parameter is a known basic type
+ param->type = type->type;
+ param->customTypeNameIndex = registerString(QString());
+ }
+
+ param->nameIndex = registerString(p->name.toString());
+ signal->parameters->append(param);
+ p = p->next;
+ }
+
+ _object->qmlSignals->append(signal);
+ } else {
+ const QStringRef &memberType = node->memberType;
+ const QStringRef &name = node->name;
+
+ bool typeFound = false;
+ QV4::CompiledData::Property::Type type;
+
+ if ((unsigned)memberType.length() == strlen("alias") &&
+ QHashedString::compare(memberType.constData(), "alias", strlen("alias"))) {
+ type = QV4::CompiledData::Property::Alias;
+ typeFound = true;
+ }
+
+ for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
+ const TypeNameToType *t = propTypeNameToTypes + ii;
+ if (t->nameLength == size_t(memberType.length()) &&
+ QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+ type = t->type;
+ typeFound = true;
+ }
+ }
+
+ if (!typeFound && memberType.at(0).isUpper()) {
+ const QStringRef &typeModifier = node->typeModifier;
+
+ if (typeModifier.isEmpty()) {
+ type = QV4::CompiledData::Property::Custom;
+ } else if ((unsigned)typeModifier.length() == strlen("list") &&
+ QHashedString::compare(typeModifier.constData(), "list", strlen("list"))) {
+ type = QV4::CompiledData::Property::CustomList;
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
+ error.setLine(node->typeModifierToken.startLine);
+ error.setColumn(node->typeModifierToken.startColumn);
+ errors << error;
+ return false;
+ }
+ typeFound = true;
+ } else if (!node->typeModifier.isNull()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
+ error.setLine(node->typeModifierToken.startLine);
+ error.setColumn(node->typeModifierToken.startColumn);
+ errors << error;
+ return false;
+ }
+
+ if (!typeFound) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Expected property type"));
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ errors << error;
+ return false;
+ }
+
+ QmlProperty *property = New<QmlProperty>();
+ property->flags = 0;
+ if (node->isReadonlyMember)
+ property->flags |= QV4::CompiledData::Property::IsReadOnly;
+ property->type = type;
+ if (type >= QV4::CompiledData::Property::Custom)
+ property->customTypeNameIndex = registerString(memberType.toString());
+ else
+ property->customTypeNameIndex = registerString(QString());
+
+ property->nameIndex = registerString(name.toString());
+
+ if (node->statement)
+ appendBinding(property->nameIndex, node->statement);
+
+ _object->properties->append(property);
+
+ if (node->isDefaultMember) {
+ if (_object->indexOfDefaultProperty != -1) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Duplicate default property"));
+ error.setLine(node->defaultToken.startLine);
+ error.setColumn(node->defaultToken.startColumn);
+ errors << error;
+ return false;
+ }
+ _object->indexOfDefaultProperty = _object->properties->count - 1;
+ }
+
+ // process QML-like initializers (e.g. property Object o: Object {})
+ // ### check if this is correct?
+ AST::Node::accept(node->binding, this);
+ }
+
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiSourceElement *node)
+{
+ if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
+ _functions << funDecl;
+ Function *f = New<Function>();
+ f->index = _functions.size() - 1;
+ _object->functions->append(f);
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
+ error.setLine(node->firstSourceLocation().startLine);
+ error.setColumn(node->firstSourceLocation().startColumn);
+ errors << error;
+ }
+ return false;
+}
+
+QString QQmlCodeGenerator::asString(AST::UiQualifiedId *node)
+{
+ QString s;
+
+ for (AST::UiQualifiedId *it = node; it; it = it->next) {
+ s.append(it->name);
+
+ if (it->next)
+ s.append(QLatin1Char('.'));
+ }
+
+ return s;
+}
+
+QStringRef QQmlCodeGenerator::asStringRef(AST::Node *node)
+{
+ if (!node)
+ return QStringRef();
+
+ return textRefAt(node->firstSourceLocation(), node->lastSourceLocation());
+}
+
+void QQmlCodeGenerator::extractVersion(QStringRef string, int *maj, int *min)
+{
+ *maj = -1; *min = -1;
+
+ if (!string.isEmpty()) {
+
+ int dot = string.indexOf(QLatin1Char('.'));
+
+ if (dot < 0) {
+ *maj = string.toString().toInt();
+ *min = 0;
+ } else {
+ const QString *s = string.string();
+ int p = string.position();
+ *maj = QStringRef(s, p, dot).toString().toInt();
+ *min = QStringRef(s, p + dot + 1, string.size() - dot - 1).toString().toInt();
+ }
+ }
+}
+
+QStringRef QQmlCodeGenerator::textRefAt(const AST::SourceLocation &first, const AST::SourceLocation &last) const
+{
+ return QStringRef(&sourceCode, first.offset, last.offset + last.length - first.offset);
+}
+
+void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, AST::Statement *statement)
+{
+ binding->value.type = QV4::CompiledData::Value::Type_Invalid;
+
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(statement)) {
+ AST::ExpressionNode *expr = stmt->expression;
+ if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) {
+ binding->value.type = QV4::CompiledData::Value::Type_String;
+ binding->value.stringIndex = registerString(lit->value.toString());
+ } else if (expr->kind == AST::Node::Kind_TrueLiteral) {
+ binding->value.type = QV4::CompiledData::Value::Type_Boolean;
+ binding->value.b = true;
+ } else if (expr->kind == AST::Node::Kind_FalseLiteral) {
+ binding->value.type = QV4::CompiledData::Value::Type_Boolean;
+ binding->value.b = false;
+ } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) {
+ binding->value.type = QV4::CompiledData::Value::Type_Number;
+ binding->value.d = lit->value;
+ } else {
+
+ if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) {
+ if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
+ binding->value.type = QV4::CompiledData::Value::Type_Number;
+ binding->value.d = -lit->value;
+ }
+ }
+ }
+ }
+
+ // Do binding instead
+ if (binding->value.type == QV4::CompiledData::Value::Type_Invalid) {
+ binding->value.type = QV4::CompiledData::Value::Type_Script;
+ _functions << statement;
+ binding->value.compiledScriptIndex = _functions.size() - 1;
+ binding->value.stringIndex = registerString(asStringRef(statement).toString());
+ }
+}
+
+void QQmlCodeGenerator::appendBinding(int propertyNameIndex, AST::Statement *value)
+{
+ Binding *binding = New<Binding>();
+ binding->propertyNameIndex = propertyNameIndex;
+ setBindingValue(binding, value);
+ _object->bindings->append(binding);
+}
+
+void QQmlCodeGenerator::appendBinding(int propertyNameIndex, int objectIndex)
+{
+ Binding *binding = New<Binding>();
+ binding->propertyNameIndex = propertyNameIndex;
+ binding->value.type = QV4::CompiledData::Value::Type_Object;
+ binding->value.objectIndex = objectIndex;
+ _object->bindings->append(binding);
+}
+
+QQmlScript::LocationSpan QQmlCodeGenerator::location(AST::SourceLocation start, AST::SourceLocation end)
+{
+ QQmlScript::LocationSpan rv;
+ rv.start.line = start.startLine;
+ rv.start.column = start.startColumn;
+ rv.end.line = end.startLine;
+ rv.end.column = end.startColumn + end.length - 1;
+ rv.range.offset = start.offset;
+ rv.range.length = end.offset + end.length - start.offset;
+ return rv;
+}
+
+QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
+{
+ jsUnitGenerator = &output.jsGenerator;
+ const QmlObject *rootObject = output.objects.at(output.indexOfRootObject);
+ int unitSize = 0;
+ QV4::CompiledData::Unit *jsUnit = jsUnitGenerator->generateUnit(&unitSize);
+
+ const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
+ const int objectOffsetTableSize = output.objects.count() * sizeof(quint32);
+
+ QHash<QmlObject*, quint32> objectOffsets;
+
+ int objectsSize = 0;
+ foreach (QmlObject *o, output.objects) {
+ objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
+ objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functions->count, o->properties->count, o->qmlSignals->count, o->bindings->count);
+
+ int signalTableSize = 0;
+ for (Signal *s = o->qmlSignals->first; s; s = s->next)
+ signalTableSize += QV4::CompiledData::Signal::calculateSize(s->parameters->count);
+
+ objectsSize += signalTableSize;
+ }
+
+ const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize;
+ char *data = (char*)malloc(totalSize);
+ memcpy(data, jsUnit, unitSize);
+ free(jsUnit);
+ jsUnit = 0;
+
+ QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit *>(data);
+ qmlUnit->header.flags |= QV4::CompiledData::Unit::IsQml;
+ qmlUnit->offsetToImports = unitSize;
+ qmlUnit->nImports = output.imports.count();
+ qmlUnit->offsetToObjects = unitSize + importSize;
+ qmlUnit->nObjects = output.objects.count();
+ qmlUnit->indexOfRootObject = output.indexOfRootObject;
+
+ // write imports
+ char *importPtr = data + qmlUnit->offsetToImports;
+ foreach (QV4::CompiledData::Import *imp, output.imports) {
+ QV4::CompiledData::Import *importToWrite = reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
+ *importToWrite = *imp;
+ importPtr += sizeof(QV4::CompiledData::Import);
+ }
+
+ // write objects
+ quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
+ char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize;
+ foreach (QmlObject *o, output.objects) {
+ *objectTable++ = objectOffsets.value(o);
+
+ QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
+ objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
+ objectToWrite->indexOfDefaultProperty = o->indexOfDefaultProperty;
+ objectToWrite->idIndex = o->idIndex;
+
+ quint32 nextOffset = sizeof(QV4::CompiledData::Object);
+
+ objectToWrite->nFunctions = o->functions->count;
+ objectToWrite->offsetToFunctions = nextOffset;
+ nextOffset += objectToWrite->nFunctions * sizeof(quint32);
+
+ objectToWrite->nProperties = o->properties->count;
+ objectToWrite->offsetToProperties = nextOffset;
+ nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property);
+
+ objectToWrite->nSignals = o->qmlSignals->count;
+ objectToWrite->offsetToSignals = nextOffset;
+ nextOffset += objectToWrite->nSignals * sizeof(quint32);
+
+ objectToWrite->nBindings = o->bindings->count;
+ objectToWrite->offsetToBindings = nextOffset;
+ nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
+
+ quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
+ for (Function *f = o->functions->first; f; f = f->next)
+ *functionsTable++ = f->index;
+
+ char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
+ for (QmlProperty *p = o->properties->first; p; p = p->next) {
+ QV4::CompiledData::Property *propertyToWrite = reinterpret_cast<QV4::CompiledData::Property*>(propertiesPtr);
+ *propertyToWrite = *p;
+ propertiesPtr += sizeof(QV4::CompiledData::Property);
+ }
+
+ char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
+ for (Binding *b = o->bindings->first; b; b = b->next) {
+ QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
+ *bindingToWrite = *b;
+ bindingPtr += sizeof(QV4::CompiledData::Binding);
+ }
+
+ quint32 *signalOffsetTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToSignals);
+ quint32 signalTableSize = 0;
+ char *signalPtr = objectPtr + nextOffset;
+ for (Signal *s = o->qmlSignals->first; s; s = s->next) {
+ *signalOffsetTable++ = signalPtr - objectPtr;
+ QV4::CompiledData::Signal *signalToWrite = reinterpret_cast<QV4::CompiledData::Signal*>(signalPtr);
+
+ signalToWrite->nameIndex = s->nameIndex;
+ signalToWrite->nParameters = s->parameters->count;
+
+ QV4::CompiledData::Parameter *parameterToWrite = reinterpret_cast<QV4::CompiledData::Parameter*>(signalPtr + sizeof(*signalToWrite));
+ for (SignalParameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
+ *parameterToWrite = *param;
+
+ int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count);
+ signalTableSize += size;
+ signalPtr += size;
+ }
+
+ objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functions->count, o->properties->count, o->qmlSignals->count, o->bindings->count);
+ objectPtr += signalTableSize;
+ }
+
+ return qmlUnit;
+}
+
+int QmlUnitGenerator::getStringId(const QString &str) const
+{
+ return jsUnitGenerator->getStringId(str);
+}
+
+void JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output)
+{
+ _module = &output->jsModule;
+ _module->setFileName(fileName);
+
+ foreach (AST::Node *node, output->functions) {
+ _env = 0;
+
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
+
+ ScanFunctions scan(this, output->code);
+ scan.enterEnvironment(node);
+ scan(function ? function->body : node);
+ scan.leaveEnvironment();
+
+ QString name;
+ if (function)
+ name = function->name.toString();
+ else
+ name = QStringLiteral("%qml-expression-entry");
+
+ defineFunction(name, node,
+ function ? function->formals : 0,
+ function ? function->body->elements : node, QmlBinding);
+
+ }
+
+ qDeleteAll(_envMap);
+ _envMap.clear();
+}
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
new file mode 100644
index 0000000000..35a40f5bc4
--- /dev/null
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** 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 QQMLCODEGENERATOR_P_H
+#define QQMLCODEGENERATOR_P_H
+
+#include <private/qqmljsast_p.h>
+#include <private/qqmlpool_p.h>
+#include <private/qqmlscript_p.h>
+#include <private/qqmljsengine_p.h>
+#include <private/qv4compiler_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qqmljsmemorypool_p.h>
+#include <private/qv4codegen_p.h>
+#include <private/qv4compiler_p.h>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtQml {
+
+using namespace QQmlJS;
+
+struct DebugStream
+{
+ DebugStream(QTextStream &stream)
+ : stream(stream)
+ , indent(0)
+ {}
+
+ template <typename T>
+ QTextStream &operator<<(const T &value)
+ {
+ return stream << QByteArray(indent * 4, ' ') << value;
+ }
+
+ QTextStream &noindent() { return stream; }
+
+ QTextStream &stream;
+ int indent;
+};
+
+template <typename T>
+struct PoolList
+{
+ PoolList()
+ : first(0)
+ , last(0)
+ , count(0)
+ {}
+
+ T *first;
+ T *last;
+ int count;
+
+ void append(T *item) {
+ item->next = 0;
+ if (last)
+ last->next = item;
+ else
+ first = item;
+ last = item;
+ ++count;
+ }
+};
+
+struct QmlObject;
+
+struct SignalParameter : public QV4::CompiledData::Parameter
+{
+ SignalParameter *next;
+};
+
+struct Signal
+{
+ int nameIndex;
+ PoolList<SignalParameter> *parameters;
+ Signal *next;
+};
+
+struct QmlProperty : public QV4::CompiledData::Property
+{
+ QmlProperty *next;
+};
+
+struct Binding : public QV4::CompiledData::Binding
+{
+ Binding *next;
+};
+
+struct Function
+{
+ int index;
+ Function *next;
+};
+
+struct QmlObject
+{
+ int inheritedTypeNameIndex;
+ int idIndex;
+ int indexOfDefaultProperty;
+
+ PoolList<QmlProperty> *properties;
+ PoolList<Signal> *qmlSignals;
+ PoolList<Binding> *bindings;
+ PoolList<Function> *functions;
+
+ void dump(DebugStream &out);
+};
+
+struct ParsedQML
+{
+ ParsedQML()
+ : jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
+ {}
+ QString code;
+ QQmlJS::Engine jsParserEngine;
+ V4IR::Module jsModule;
+ QList<QV4::CompiledData::Import*> imports;
+ int indexOfRootObject;
+ QList<QmlObject*> objects;
+ QList<AST::Node*> functions; // FunctionDeclaration, Statement or Expression
+ QV4::Compiler::JSUnitGenerator jsGenerator;
+
+ QString stringAt(int index) const { return jsGenerator.strings.value(index); }
+};
+
+// Doesn't really generate code per-se, but more the data structure
+struct Q_QML_EXPORT QQmlCodeGenerator : public AST::Visitor
+{
+ QQmlCodeGenerator();
+ bool generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output);
+
+ using AST::Visitor::visit;
+ using AST::Visitor::endVisit;
+
+ virtual bool visit(AST::UiArrayMemberList *ast);
+ virtual bool visit(AST::UiImport *ast);
+ virtual bool visit(AST::UiImportList *ast);
+ virtual bool visit(AST::UiObjectInitializer *ast);
+ virtual bool visit(AST::UiObjectMemberList *ast);
+ virtual bool visit(AST::UiParameterList *ast);
+ virtual bool visit(AST::UiProgram *);
+ virtual bool visit(AST::UiQualifiedId *ast);
+ virtual bool visit(AST::UiArrayBinding *ast);
+ virtual bool visit(AST::UiObjectBinding *ast);
+ virtual bool visit(AST::UiObjectDefinition *ast);
+ virtual bool visit(AST::UiPublicMember *ast);
+ virtual bool visit(AST::UiScriptBinding *ast);
+ virtual bool visit(AST::UiSourceElement *ast);
+
+ void accept(AST::Node *node);
+
+ // returns index in _objects
+ int defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer);
+ int defineQMLObject(AST::UiObjectDefinition *node)
+ { return defineQMLObject(node->qualifiedTypeNameId, node->initializer); }
+
+ static QString asString(AST::UiQualifiedId *node);
+ QStringRef asStringRef(AST::Node *node);
+ static void extractVersion(QStringRef string, int *maj, int *min);
+ QStringRef textRefAt(const AST::SourceLocation &loc) const
+ { return QStringRef(&sourceCode, loc.offset, loc.length); }
+ QStringRef textRefAt(const AST::SourceLocation &first,
+ const AST::SourceLocation &last) const;
+ static QQmlScript::LocationSpan location(AST::UiQualifiedId *id)
+ {
+ return location(id->identifierToken, id->identifierToken);
+ }
+
+ void setBindingValue(QV4::CompiledData::Binding *binding, AST::Statement *statement);
+
+ void appendBinding(int propertyNameIndex, AST::Statement *value);
+ void appendBinding(int propertyNameIndex, int objectIndex);
+
+ static QQmlScript::LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
+
+ int registerString(const QString &str) const { return jsGenerator->registerString(str); }
+ template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+
+ QList<QQmlError> errors;
+
+ QList<QV4::CompiledData::Import*> _imports;
+ QList<QmlObject*> _objects;
+ QList<AST::Node*> _functions;
+
+ QmlObject *_object;
+
+ QQmlJS::MemoryPool *pool;
+ QString sourceCode;
+ QV4::Compiler::JSUnitGenerator *jsGenerator;
+};
+
+struct Q_QML_EXPORT QmlUnitGenerator
+{
+ QmlUnitGenerator()
+ : jsUnitGenerator(0)
+ {
+ }
+
+ QV4::CompiledData::QmlUnit *generate(ParsedQML &output);
+
+private:
+ int getStringId(const QString &str) const;
+
+ QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
+};
+
+struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
+{
+ JSCodeGen()
+ : QQmlJS::Codegen(/*strict mode*/false)
+ {}
+
+ void generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output);
+
+private:
+ V4IR::Module jsModule;
+};
+
+} // namespace QtQml
+
+QT_END_NAMESPACE
+
+#endif // QQMLCODEGENERATOR_P_H
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 293086378e..f4822fe26e 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1749,7 +1749,7 @@ bool Codegen::visit(FunctionDeclaration * ast)
V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
- AST::SourceElements *body, Mode mode,
+ AST::Node *body, Mode mode,
const QStringList &inheritedLocals)
{
qSwap(_mode, mode); // enter function code.
@@ -1851,7 +1851,13 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
}
- sourceElements(body);
+ if (AST::SourceElements *elements = AST::cast<AST::SourceElements*>(body))
+ sourceElements(elements);
+ else if (body) {
+ Q_ASSERT(_mode == QmlBinding);
+ _block->nextLocation = ast->firstSourceLocation();
+ accept(body);
+ }
_function->insertBasicBlock(_exitBlock);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 2d2ca55f8d..385cddefe3 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -282,7 +282,7 @@ protected:
V4IR::Function *defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
- AST::SourceElements *body,
+ AST::Node *body,
Mode mode = FunctionCode,
const QStringList &inheritedLocals = QStringList());
@@ -435,7 +435,7 @@ protected:
QList<QQmlError> _errors;
- class ScanFunctions: Visitor
+ class ScanFunctions: protected Visitor
{
typedef QV4::TemporaryAssignment<bool> TemporaryBoolAssignment;
public:
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 237cdf7d62..50ed39f0d8 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -178,9 +178,9 @@ struct Unit
return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
}
- static int calculateSize(uint nStrings, uint nFunctions, uint nRegExps,
+ static int calculateSize(uint headerSize, uint nStrings, uint nFunctions, uint nRegExps,
uint nLookups, uint nClasses) {
- return (sizeof(Unit)
+ return (headerSize
+ (nStrings + nFunctions + nClasses) * sizeof(uint)
+ nRegExps * RegExp::calculateSize()
+ nLookups * Lookup::calculateSize()
@@ -225,77 +225,168 @@ struct Function
struct Value
{
- quint32 type; // Invalid, Boolean, Number, String, Function, Object, ListOfObjects
+ enum ValueType {
+ Type_Invalid,
+ Type_Boolean,
+ Type_Number,
+ Type_String,
+ Type_Script,
+ Type_Object
+ };
+
+ quint32 type;
union {
bool b;
- int i;
double d;
- quint32 offsetToString;
- quint32 offsetToFunction;
- quint32 offsetToObject;
+ quint32 compiledScriptIndex; // used when Type_Script
+ quint32 objectIndex;
};
+ quint32 stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
};
struct Binding
{
- quint32 offsetToPropertyName;
+ quint32 propertyNameIndex;
Value value;
};
struct Parameter
{
- quint32 offsetToName;
+ quint32 nameIndex;
quint32 type;
- quint32 offsetToCustomTypeName;
+ quint32 customTypeNameIndex;
quint32 reserved;
};
struct Signal
{
- quint32 offsetToName;
+ quint32 nameIndex;
quint32 nParameters;
- Parameter parameters[1];
+ // Parameter parameters[1];
+
+ const Parameter *parameterAt(int idx) const {
+ return reinterpret_cast<const Parameter*>(this + 1) + idx;
+ }
+
+ static int calculateSize(int nParameters) {
+ return (sizeof(Signal)
+ + nParameters * sizeof(Parameter)
+ + 7) & ~0x7;
+ }
};
struct Property
{
- quint32 offsetToName;
+ enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
+ Font, Time, Date, DateTime, Rect, Point, Size,
+ Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
+ Alias, Custom, CustomList };
+
+ enum Flags {
+ IsReadOnly = 0x1
+ };
+
+ quint32 nameIndex;
quint32 type;
- quint32 offsetToCustomTypeName;
- quint32 flags; // default, readonly
- Value value;
+ quint32 customTypeNameIndex;
+ quint32 flags; // readonly
};
struct Object
{
- quint32 offsetToInheritedTypeName;
- quint32 offsetToId;
- quint32 offsetToDefaultProperty;
+ quint32 inheritedTypeNameIndex;
+ quint32 idIndex;
+ quint32 indexOfDefaultProperty;
quint32 nFunctions;
quint32 offsetToFunctions;
quint32 nProperties;
quint32 offsetToProperties;
quint32 nSignals;
- quint32 offsetToSignals;
+ quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
quint32 nBindings;
quint32 offsetToBindings;
// Function[]
// Property[]
// Signal[]
// Binding[]
+
+ static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nSignals, int nBindings)
+ {
+ return ( sizeof(Object)
+ + nFunctions * sizeof(quint32)
+ + nProperties * sizeof(Property)
+ + nSignals * sizeof(quint32)
+ + nBindings * sizeof(Binding)
+ + 0x7
+ ) & ~0x7;
+ }
+
+ const quint32 *functionOffsetTable() const
+ {
+ return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
+ }
+
+ const Property *propertyTable() const
+ {
+ return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
+ }
+
+ const Binding *bindingTable() const
+ {
+ return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
+ }
+
+ const Signal *signalAt(int idx) const
+ {
+ const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
+ const uint offset = offsetTable[idx];
+ return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
+ }
};
-struct Imports
+struct Location
{
+ int line;
+ int column;
+};
+
+struct Import
+{
+ enum ImportType {
+ ImportLibrary = 0x1,
+ ImportFile = 0x2,
+ ImportScript = 0x3
+ };
+ quint32 type;
+
+ quint32 uriIndex;
+ quint32 qualifierIndex;
+
+ qint32 majorVersion;
+ qint32 minorVersion;
+
+ Location location;
};
struct QmlUnit
{
Unit header;
- int offsetToTypeName;
- Imports imports;
- Object object;
+ quint32 nImports;
+ quint32 offsetToImports;
+ quint32 nObjects;
+ quint32 offsetToObjects;
+ quint32 indexOfRootObject;
+
+ const Import *importAt(int idx) const {
+ return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
+ }
+
+ const Object *objectAt(int idx) const {
+ const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
+ const uint offset = offsetTable[idx];
+ return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
+ }
};
// This is how this hooks into the existing structures:
@@ -304,7 +395,7 @@ struct QmlUnit
// CompilationUnit * (for functions that need to clean up)
// CompiledData::Function *compiledFunction
-struct CompilationUnit
+struct Q_QML_EXPORT CompilationUnit
{
CompilationUnit()
: refCount(0)
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 322a39932a..6781fdfe72 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -44,11 +44,14 @@
#include <qv4isel_p.h>
#include <qv4engine_p.h>
-QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::V4IR::Module *module)
+QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::V4IR::Module *module, int headerSize)
: irModule(module)
, stringDataSize(0)
, jsClassDataSize(0)
{
+ if (headerSize == -1)
+ headerSize = sizeof(QV4::CompiledData::Unit);
+ this->headerSize = headerSize;
}
int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
@@ -148,7 +151,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(QQmlJS::V4IR::ExprList *args
return jsClasses.size() - 1;
}
-QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
+QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *totalUnitSize)
{
registerString(irModule->fileName);
foreach (QQmlJS::V4IR::Function *f, irModule->functions) {
@@ -159,7 +162,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
registerString(*f->locals.at(i));
}
- int unitSize = QV4::CompiledData::Unit::calculateSize(strings.size(), irModule->functions.size(), regexps.size(), lookups.size(), jsClasses.count());
+ int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(), lookups.size(), jsClasses.count());
uint functionDataSize = 0;
for (int i = 0; i < irModule->functions.size(); ++i) {
@@ -174,7 +177,11 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount);
}
- char *data = (char *)malloc(unitSize + functionDataSize + stringDataSize + jsClassDataSize);
+ const int totalSize = unitSize + functionDataSize + stringDataSize + jsClassDataSize;
+ if (totalUnitSize)
+ *totalUnitSize = totalSize;
+ char *data = (char *)malloc(totalSize);
+ memset(data, 0, totalSize);
QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic));
@@ -182,7 +189,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
unit->flags = QV4::CompiledData::Unit::IsJavascript;
unit->version = 1;
unit->stringTableSize = strings.size();
- unit->offsetToStringTable = sizeof(QV4::CompiledData::Unit);
+ unit->offsetToStringTable = headerSize;
unit->functionTableSize = irModule->functions.size();
unit->offsetToFunctionTable = unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
unit->lookupTableSize = lookups.count();
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 6c50073a24..b875833463 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -57,8 +57,8 @@ struct JSClassMember;
namespace Compiler {
-struct JSUnitGenerator {
- JSUnitGenerator(QQmlJS::V4IR::Module *module);
+struct Q_QML_EXPORT JSUnitGenerator {
+ JSUnitGenerator(QQmlJS::V4IR::Module *module, int headerSize = -1);
QQmlJS::V4IR::Module *irModule;
@@ -75,19 +75,20 @@ struct JSUnitGenerator {
int registerJSClass(QQmlJS::V4IR::ExprList *args);
- QV4::CompiledData::Unit *generateUnit();
+ QV4::CompiledData::Unit *generateUnit(int *totalUnitSize = 0);
// Returns bytes written
int writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction);
QHash<QString, int> stringToId;
QStringList strings;
- int stringDataSize;
+ uint stringDataSize;
QHash<QQmlJS::V4IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction;
QList<QList<CompiledData::JSClassMember> > jsClasses;
- int jsClassDataSize;
+ uint jsClassDataSize;
+ uint headerSize;
};
}
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 1d277270ca..cefc053ac4 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -685,8 +685,6 @@ void *InstructionSelection::addConstantTable(QVector<Value> *values)
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
{
- compilationUnit->data = jsGenerator->generateUnit();
- compilationUnit->ownsData = true;
compilationUnit->codeRefs.resize(irModule->functions.size());
int i = 0;
foreach (V4IR::Function *irFunction, irModule->functions)
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index bef2f64c3e..d4dc5460b7 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -300,8 +300,6 @@ void InstructionSelection::run(V4IR::Function *function)
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
{
- compilationUnit->data = jsGenerator->generateUnit();
- compilationUnit->ownsData = true;
compilationUnit->codeRefs.resize(irModule->functions.size());
int i = 0;
foreach (V4IR::Function *irFunction, irModule->functions)
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 4d475a1bd0..5a1a6f5341 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -78,7 +78,7 @@ EvalInstructionSelection::~EvalInstructionSelection()
EvalISelFactory::~EvalISelFactory()
{}
-QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile()
+QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData)
{
Function *rootFunction = irModule->rootFunction;
if (!rootFunction)
@@ -86,7 +86,12 @@ QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile()
foreach (V4IR::Function *f, irModule->functions)
run(f);
- return backendCompileStep();
+ QV4::CompiledData::CompilationUnit *unit = backendCompileStep();
+ if (generateUnitData) {
+ unit->data = jsGenerator->generateUnit();
+ unit->ownsData = true;
+ }
+ return unit;
}
void IRDecoder::visitMove(V4IR::Move *s)
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index ac6ea64c9f..8824b677af 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -65,7 +65,7 @@ public:
EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
virtual ~EvalInstructionSelection() = 0;
- QV4::CompiledData::CompilationUnit *compile();
+ QV4::CompiledData::CompilationUnit *compile(bool generateUnitData = true);
void setUseFastLookups(bool b) { useFastLookups = b; }
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index e70cf100ce..81aa727eda 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -626,9 +626,7 @@ Function *Module::newFunction(const QString &name, Function *outer)
Module::~Module()
{
- foreach (Function *f, functions) {
- delete f;
- }
+ qDeleteAll(functions);
}
void Module::setFileName(const QString &name)
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 595955a8ec..735dc558e1 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -47,7 +47,6 @@
#include <QtCore/QByteArray>
#include <QtCore/qurl.h>
-#include <config.h>
#include "qv4value_def_p.h"
#include <private/qv4compileddata_p.h>
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 9d0fed34fe..aef8ac8838 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -59,39 +59,44 @@
using namespace QV4;
-struct QmlBindingWrapper : FunctionObject
+QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Object *qml)
+ : FunctionObject(scope, scope->engine->id_eval)
+ , qml(qml)
{
- Q_MANAGED
+ vtbl = &static_vtbl;
+ function = f;
+ function->compilationUnit->ref();
+ usesArgumentsObject = function->usesArgumentsObject();
+ needsActivation = function->needsActivation();
+ defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(1));
+
+ qmlContext = scope->engine->current->newQmlContext(this, qml);
+ scope->engine->popContext();
+}
- QmlBindingWrapper(ExecutionContext *scope, Function *f, Object *qml)
- : FunctionObject(scope, scope->engine->id_eval)
- , qml(qml)
- {
- vtbl = &static_vtbl;
- function = f;
- function->compilationUnit->ref();
- usesArgumentsObject = function->usesArgumentsObject();
- needsActivation = function->needsActivation();
- defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(1));
-
- qmlContext = scope->engine->current->newQmlContext(this, qml);
- scope->engine->popContext();
- }
+Value QmlBindingWrapper::call(Managed *that, const CallData &)
+{
+ ExecutionEngine *engine = that->engine();
+ QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
- static Value call(Managed *that, const CallData &);
- static void markObjects(Managed *m)
- {
- QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
- if (wrapper->qml)
- wrapper->qml->mark();
- FunctionObject::markObjects(m);
- wrapper->qmlContext->mark();
- }
+ CallContext *ctx = This->qmlContext;
+ std::fill(ctx->locals, ctx->locals + ctx->function->varCount, Value::undefinedValue());
+ engine->pushContext(ctx);
+ Value result = This->function->code(ctx, This->function->codeData);
+ engine->popContext();
-private:
- Object *qml;
- CallContext *qmlContext;
-};
+ return result;
+
+}
+
+void QmlBindingWrapper::markObjects(Managed *m)
+{
+ QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
+ if (wrapper->qml)
+ wrapper->qml->mark();
+ FunctionObject::markObjects(m);
+ wrapper->qmlContext->mark();
+}
DEFINE_MANAGED_VTABLE(QmlBindingWrapper);
@@ -121,22 +126,6 @@ struct CompilationUnitHolder : public QV4::Object
DEFINE_MANAGED_VTABLE(CompilationUnitHolder);
-Value QmlBindingWrapper::call(Managed *that, const CallData &)
-{
- ExecutionEngine *engine = that->engine();
- QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
-
- CallContext *ctx = This->qmlContext;
- std::fill(ctx->locals, ctx->locals + ctx->function->varCount, Value::undefinedValue());
- engine->pushContext(ctx);
- Value result = This->function->code(ctx, This->function->codeData);
- engine->popContext();
-
- return result;
-
-}
-
-
Script::~Script()
{
}
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 250fd73704..b3bce6b427 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -43,6 +43,7 @@
#include "qv4global_p.h"
#include "qv4engine_p.h"
+#include "qv4functionobject_p.h"
QT_BEGIN_NAMESPACE
@@ -50,6 +51,19 @@ namespace QV4 {
struct ExecutionContext;
+struct QmlBindingWrapper : FunctionObject {
+ Q_MANAGED
+
+ QmlBindingWrapper(ExecutionContext *scope, Function *f, Object *qml);
+
+ static Value call(Managed *that, const CallData &);
+ static void markObjects(Managed *m);
+
+private:
+ Object *qml;
+ CallContext *qmlContext;
+};
+
struct Q_QML_EXPORT Script {
Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index dae76ede32..77b0334c7e 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -54,7 +54,8 @@ SOURCES += \
$$PWD/qqmllistwrapper.cpp \
$$PWD/qqmlcontextwrapper.cpp \
$$PWD/qqmlvaluetypewrapper.cpp \
- $$PWD/qqmltypewrapper.cpp
+ $$PWD/qqmltypewrapper.cpp \
+ $$PWD/qqmlobjectcreator.cpp
HEADERS += \
$$PWD/qqmlglobal_p.h \
@@ -130,7 +131,8 @@ HEADERS += \
$$PWD/qqmllistwrapper_p.h \
$$PWD/qqmlcontextwrapper_p.h \
$$PWD/qqmlvaluetypewrapper_p.h \
- $$PWD/qqmltypewrapper_p.h
+ $$PWD/qqmltypewrapper_p.h \
+ $$PWD/qqmlobjectcreator_p.h
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index 40d42d8284..8b04d823e2 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -60,6 +60,10 @@
QT_BEGIN_NAMESPACE
+namespace QtQml {
+class QmlObjectCreator;
+}
+
class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
{
public:
@@ -150,6 +154,7 @@ private:
friend class QQmlVME;
friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
friend class QV4Bindings;
+ friend class QtQml::QmlObjectCreator;
typedef QSharedPointer<QQmlAbstractBinding> SharedPointer;
// To save memory, we also store the rarely used weakPointer() instance in here
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index abe278f570..a2e323a129 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -87,7 +87,7 @@ int QQmlCompiledData::indexForUrl(const QUrl &data)
QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false),
- rootPropertyCache(0)
+ rootPropertyCache(0), compilationUnit(0), qmlUnit(0)
{
Q_ASSERT(engine);
@@ -127,6 +127,10 @@ QQmlCompiledData::~QQmlCompiledData()
if (rootPropertyCache)
rootPropertyCache->release();
+
+ if (compilationUnit)
+ compilationUnit->deref();
+ free(qmlUnit);
}
void QQmlCompiledData::clear()
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index bc013358f5..ca825a923d 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -70,6 +70,13 @@
QT_BEGIN_NAMESPACE
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+struct QmlUnit;
+}
+}
+
class QQmlEngine;
class QQmlComponent;
class QQmlContext;
@@ -125,6 +132,11 @@ public:
QList<QQmlScriptData *> scripts;
QList<QUrl> urls;
+ // --- new compiler
+ QV4::CompiledData::CompilationUnit *compilationUnit;
+ QV4::CompiledData::QmlUnit *qmlUnit;
+ // ---
+
struct Instruction {
#define QML_INSTR_DATA_TYPEDEF(I, FMT) typedef QQmlInstructionData<QQmlInstruction::I> I;
FOR_EACH_QML_INSTR(QML_INSTR_DATA_TYPEDEF)
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 5f3a2e971c..ff961c7822 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -893,8 +893,16 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
state.completePending = true;
enginePriv->referenceScarceResources();
- state.vme.init(context, cc, start, creationContext);
- QObject *rv = state.vme.execute(&state.errors);
+ QObject *rv = 0;
+ if (enginePriv->useNewCompiler) {
+ state.creator = new QtQml::QmlObjectCreator(engine, context, cc);
+ rv = state.creator->create();
+ if (!rv)
+ state.errors = state.creator->errors;
+ } else {
+ state.vme.init(context, cc, start, creationContext);
+ rv = state.vme.execute(&state.errors);
+ }
enginePriv->dereferenceScarceResources();
if (rv) {
@@ -934,14 +942,22 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
state->errors.clear();
state->completePending = true;
- state->vme.initDeferred(object);
- state->vme.execute(&state->errors);
+ if (enginePriv->useNewCompiler) {
+ // ###
+ } else {
+ state->vme.initDeferred(object);
+ state->vme.execute(&state->errors);
+ }
}
void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
{
if (state->completePending) {
- state->vme.complete();
+ if (enginePriv->useNewCompiler) {
+ // ###
+ } else {
+ state->vme.complete();
+ }
state->completePending = false;
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 439f1fcdd9..3bd0a194df 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -62,6 +62,7 @@
#include "qqmlerror.h"
#include "qqml.h"
#include <private/qqmlprofilerservice_p.h>
+#include <private/qqmlobjectcreator_p.h>
#include <QtCore/QString>
#include <QtCore/QStringList>
@@ -105,9 +106,20 @@ public:
QQmlCompiledData *cc;
struct ConstructionState {
- ConstructionState() : completePending(false) {}
-
+ ConstructionState()
+ : creator(0)
+ , completePending(false)
+ {}
+ ~ConstructionState()
+ {
+ delete creator;
+ }
+
+ // --- new compiler
+ QtQml::QmlObjectCreator *creator;
+ // --- old compiler
QQmlVME vme;
+ // ---
QList<QQmlError> errors;
bool completePending;
};
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 39c3399917..971836f783 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -510,6 +510,7 @@ the same object as is returned from the Qt.include() call.
*/
// Qt.include() is implemented in qv4include.cpp
+DEFINE_BOOL_CONFIG_OPTION(qmlUseNewCompiler, QML_NEW_COMPILER)
QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
: propertyCapture(0), rootContext(0), isDebugging(false),
@@ -520,6 +521,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
{
+ useNewCompiler = qmlUseNewCompiler();
}
QQmlEnginePrivate::~QQmlEnginePrivate()
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index c57c70fa40..b57c84ceae 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -144,6 +144,7 @@ public:
QQmlContext *rootContext;
bool isDebugging;
+ bool useNewCompiler;
bool outputWarningsToStdErr;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
new file mode 100644
index 0000000000..8fdfe8e4f1
--- /dev/null
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -0,0 +1,686 @@
+/****************************************************************************
+**
+** 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 "qqmlobjectcreator_p.h"
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlstringconverters_p.h>
+
+QT_USE_NAMESPACE
+
+using namespace QtQml;
+
+static void removeBindingOnProperty(QObject *o, int index)
+{
+ int coreIndex = index & 0x0000FFFF;
+ int valueTypeIndex = (index & 0xFFFF0000 ? index >> 16 : -1);
+
+ QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0);
+ if (binding) binding->destroy();
+}
+
+QmlObjectCreator::QmlObjectCreator(QQmlEngine *engine, QQmlContextData *contextData, QQmlCompiledData *runtimeData)
+ : engine(engine)
+ , unit(runtimeData->qmlUnit)
+ , jsUnit(runtimeData->compilationUnit)
+ , context(contextData)
+ , typeNameCache(0)
+ , runtimeData(runtimeData)
+ , imports(&QQmlEnginePrivate::get(engine)->typeLoader)
+ , _object(0)
+ , _ddata(0)
+ , _propertyCache(0)
+{
+ typeNameCache = new QQmlTypeNameCache;
+
+ QQmlImportDatabase *idb = &QQmlEnginePrivate::get(engine)->importDatabase;
+
+ for (uint i = 0; i < unit->nImports; ++i) {
+ const QV4::CompiledData::Import *import = unit->importAt(i);
+ if (import->type == QV4::CompiledData::Import::ImportLibrary) {
+ imports.addLibraryImport(idb, stringAt(import->uriIndex), stringAt(import->qualifierIndex),
+ import->majorVersion, import->minorVersion, /*qmldir identifier*/ QString(),
+ /*qmldir url*/ QString(), /*incomplete*/ false, &errors);
+ } else {
+ // ###
+ }
+ }
+
+ imports.populateCache(typeNameCache);
+ context->imports = typeNameCache;
+ context->imports->addref();
+
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ if (runtimeData->compilationUnit && !runtimeData->compilationUnit->engine)
+ runtimeData->compilationUnit->linkToEngine(v4);
+}
+
+QVector<QQmlAbstractBinding*> QmlObjectCreator::setupBindings(const QV4::CompiledData::Object *obj, QV4::Object *qmlGlobal)
+{
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
+ QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ int propertyWriteStatus = -1;
+ QVariant fallbackVariantValue;
+
+ QVector<QQmlAbstractBinding*> createdDynamicBindings(obj->nBindings, 0);
+
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ QString name = stringAt(binding->propertyNameIndex);
+
+ if (name.isEmpty() && binding->value.type == QV4::CompiledData::Value::Type_Object) {
+ create(binding->value.objectIndex, _object);
+ continue;
+ }
+
+ QQmlPropertyData *property = _propertyCache->property(name, _object, context);
+
+ if (_ddata->hasBindingBit(property->coreIndex))
+ removeBindingOnProperty(_object, property->coreIndex);
+
+ if (binding->value.type == QV4::CompiledData::Value::Type_Script) {
+ QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QV4::FunctionObject *function = new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, runtimeFunction, qmlGlobal);
+ QQmlBinding *binding = new QQmlBinding(QV4::Value::fromObject(function), _object, context,
+ QString(), 0, 0); // ###
+
+ binding->setTarget(_object, *property, context);
+ binding->addToObject();
+
+ createdDynamicBindings[i] = binding;
+ binding->m_mePtr = &createdDynamicBindings[i];
+ continue;
+ }
+
+ void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
+
+ // shortcuts
+#if 0
+ if (property->propType == QMetaType::Double && binding->value.type == QV4::CompiledData::Value::Type_Number) {
+ argv[0] = const_cast<double*>(&binding->value.d);
+ } else if (property->propType == QMetaType::Bool && binding->value.type == QV4::CompiledData::Value::Type_Boolean) {
+ argv[0] = const_cast<bool*>(&binding->value.b);
+ } else
+#endif
+ {
+ // fallback
+ fallbackVariantValue = variantForBinding(property->propType, binding);
+
+ if (property->propType == QMetaType::QVariant)
+ argv[0] = &fallbackVariantValue;
+ else
+ argv[0] = fallbackVariantValue.data();
+ }
+
+ QMetaObject::metacall(_object, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+
+ return createdDynamicBindings;
+}
+
+void QmlObjectCreator::setupFunctions(const QV4::CompiledData::Object *obj, QV4::Object *qmlGlobal)
+{
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(_object);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
+ const quint32 *functionIdx = obj->functionOffsetTable();
+ for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIdx) {
+ QV4::Function *function = jsUnit->runtimeFunctions[*functionIdx];
+ const QString name = function->name->toQString();
+
+ QQmlPropertyData *property = _propertyCache->property(name, _object, context);
+ if (!property->isVMEFunction())
+ continue;
+
+ QV4::FunctionObject *v4Function = new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, function, qmlGlobal);
+ vme->setVmeMethod(property->coreIndex, QV4::Value::fromObject(v4Function));
+ }
+}
+
+QObject *QmlObjectCreator::create(int index, QObject *parent)
+{
+ const QV4::CompiledData::Object *obj = unit->objectAt(index);
+
+ QQmlTypeNameCache::Result res = typeNameCache->query(stringAt(obj->inheritedTypeNameIndex));
+ if (!res.isValid())
+ return 0;
+
+ QObject *result = res.type->create();
+ // ### use no-event variant
+ if (parent)
+ result->setParent(parent);
+
+ QQmlData *declarativeData = QQmlData::get(result, /*create*/true);
+
+ qSwap(_object, result);
+ qSwap(_ddata, declarativeData);
+
+ context->addObject(_object);
+
+ // ### avoid _object->metaObject
+ QQmlPropertyCache *baseTypeCache = QQmlEnginePrivate::get(engine)->cache(_object->metaObject());
+ baseTypeCache->addref();
+
+ QQmlPropertyCache *cache = 0;
+ QByteArray vmeMetaData;
+ bool needCustomMetaObject = createVMEMetaObjectAndPropertyCache(obj, baseTypeCache, &cache, &vmeMetaData);
+ cache->addref();
+
+ baseTypeCache->release();
+ baseTypeCache = 0;
+
+ qSwap(_propertyCache, cache);
+
+ if (needCustomMetaObject) {
+ runtimeData->datas.append(vmeMetaData);
+ // install on _object
+ (void)new QQmlVMEMetaObject(_object, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(runtimeData->datas.last().constData()));
+ if (_ddata->propertyCache)
+ _ddata->propertyCache->release();
+ _ddata->propertyCache = _propertyCache;
+ _ddata->propertyCache->addref();
+ }
+
+ QV4::Value scopeObject = QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _object);
+
+ QVector<QQmlAbstractBinding*> dynamicBindings = setupBindings(obj, scopeObject.asObject());
+ setupFunctions(obj, scopeObject.asObject());
+
+ // ### do this later when requested
+ for (int i = 0; i < dynamicBindings.count(); ++i) {
+ QQmlAbstractBinding *b = dynamicBindings.at(i);
+ if (!b)
+ continue;
+ b->m_mePtr = 0;
+ QQmlData *data = QQmlData::get(b->object());
+ Q_ASSERT(data);
+ data->clearPendingBindingBit(b->propertyIndex());
+ b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::DontRemoveBinding);
+ }
+
+ qSwap(_propertyCache, cache);
+ qSwap(_ddata, declarativeData);
+ qSwap(_object, result);
+
+ cache->release();
+
+ return result;
+}
+
+// ###
+#define COMPILE_EXCEPTION(token, desc) {}
+
+static QAtomicInt classIndexCounter(0);
+
+bool QmlObjectCreator::createVMEMetaObjectAndPropertyCache(const QV4::CompiledData::Object *obj, QQmlPropertyCache *baseTypeCache, QQmlPropertyCache **outputCache, QByteArray *vmeMetaObjectData) const
+{
+ if (!obj->nProperties) {
+ *outputCache = baseTypeCache;
+ return false;
+ }
+
+ QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(engine, obj->nProperties, /*methodCount*/0, /*signalCount*/0);
+ *outputCache = cache;
+
+ vmeMetaObjectData->clear();
+
+ struct TypeData {
+ QV4::CompiledData::Property::Type dtype;
+ int metaType;
+ } builtinTypes[] = {
+ { QV4::CompiledData::Property::Var, QMetaType::QVariant },
+ { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
+ { QV4::CompiledData::Property::Int, QMetaType::Int },
+ { QV4::CompiledData::Property::Bool, QMetaType::Bool },
+ { QV4::CompiledData::Property::Real, QMetaType::Double },
+ { QV4::CompiledData::Property::String, QMetaType::QString },
+ { QV4::CompiledData::Property::Url, QMetaType::QUrl },
+ { QV4::CompiledData::Property::Color, QMetaType::QColor },
+ { QV4::CompiledData::Property::Font, QMetaType::QFont },
+ { QV4::CompiledData::Property::Time, QMetaType::QTime },
+ { QV4::CompiledData::Property::Date, QMetaType::QDate },
+ { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
+ { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
+ { QV4::CompiledData::Property::Point, QMetaType::QPointF },
+ { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
+ { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
+ { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
+ { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
+ { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
+ { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
+ };
+ static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
+
+ QByteArray newClassName;
+
+ if (false /* ### compileState->root == obj && !compileState->nested*/) {
+#if 0 // ###
+ QString path = output->url.path();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash > -1) {
+ QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
+ if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
+ newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
+ QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
+ }
+#endif
+ }
+ if (newClassName.isEmpty()) {
+ newClassName = QQmlMetaObject(baseTypeCache).className();
+ newClassName.append("_QML_");
+ newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
+ }
+
+ cache->_dynamicClassName = newClassName;
+
+ int aliasCount = 0;
+ int varPropCount = 0;
+
+ const QV4::CompiledData::Property *p = obj->propertyTable();
+ for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
+
+ if (p->type == QV4::CompiledData::Property::Alias)
+ aliasCount++;
+ else if (p->type == QV4::CompiledData::Property::Var)
+ varPropCount++;
+
+#if 0 // ### Do this elsewhere
+ // No point doing this for both the alias and non alias cases
+ QQmlPropertyData *d = property(obj, p->name);
+ if (d && d->isFinal())
+ COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
+#endif
+ }
+
+ typedef QQmlVMEMetaData VMD;
+
+ QByteArray &dynamicData = *vmeMetaObjectData = QByteArray(sizeof(QQmlVMEMetaData)
+ + obj->nProperties * sizeof(VMD::PropertyData)
+ + obj->nFunctions * sizeof(VMD::MethodData)
+ + aliasCount * sizeof(VMD::AliasData), 0);
+
+ int effectivePropertyIndex = cache->propertyIndexCacheStart;
+ int effectiveMethodIndex = cache->methodIndexCacheStart;
+
+ // For property change signal override detection.
+ // We prepopulate a set of signal names which already exist in the object,
+ // and throw an error if there is a signal/method defined as an override.
+ QSet<QString> seenSignals;
+ seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
+ QQmlPropertyCache *parentCache = cache;
+ while ((parentCache = parentCache->parent())) {
+ if (int pSigCount = parentCache->signalCount()) {
+ int pSigOffset = parentCache->signalOffset();
+ for (int i = pSigOffset; i < pSigCount; ++i) {
+ QQmlPropertyData *currPSig = parentCache->signal(i);
+ // XXX TODO: find a better way to get signal name from the property data :-/
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
+ iter != parentCache->stringCache.end(); ++iter) {
+ if (currPSig == (*iter).second) {
+ seenSignals.insert(iter.key());
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // First set up notify signals for properties - first normal, then var, then alias
+ enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
+ for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
+
+ if (ii == NSS_Var && varPropCount == 0) continue;
+ else if (ii == NSS_Alias && aliasCount == 0) continue;
+
+ const QV4::CompiledData::Property *p = obj->propertyTable();
+ for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
+ if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias ||
+ p->type == QV4::CompiledData::Property::Var)) ||
+ ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) ||
+ ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias)))
+ continue;
+
+ quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
+ QQmlPropertyData::IsVMESignal;
+
+ QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
+ seenSignals.insert(changedSigName);
+
+ cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
+ }
+ }
+
+ // Dynamic signals
+ for (uint i = 0; i < obj->nSignals; ++i) {
+ const QV4::CompiledData::Signal *s = obj->signalAt(i);
+ const int paramCount = s->nParameters;
+
+ QList<QByteArray> names;
+ QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
+
+ if (paramCount) {
+ paramTypes[0] = paramCount;
+
+ for (int i = 0; i < paramCount; ++i) {
+ const QV4::CompiledData::Parameter *param = s->parameterAt(i);
+ names.append(stringAt(param->nameIndex).toUtf8());
+ if (param->type < builtinTypeCount) {
+ // built-in type
+ paramTypes[i + 1] = builtinTypes[param->type].metaType;
+ } else {
+ // lazily resolved type
+ Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
+ QQmlType *qmltype = 0;
+ if (!imports.resolveType(stringAt(param->customTypeNameIndex), &qmltype, 0, 0, 0))
+ COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(s->parameterTypeNames.at(i).toString()));
+
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = QQmlEnginePrivate::get(engine)->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ QQmlCompiledData *data = tdata->compiledData();
+
+ paramTypes[i + 1] = data->metaTypeId;
+
+ tdata->release();
+ } else {
+ paramTypes[i + 1] = qmltype->typeId();
+ }
+ }
+ }
+ }
+
+ ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
+
+ quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
+ QQmlPropertyData::IsVMESignal;
+ if (paramCount)
+ flags |= QQmlPropertyData::HasArguments;
+
+ QString signalName = stringAt(s->nameIndex);
+ if (seenSignals.contains(signalName)) {
+#if 0 // ###
+ const QQmlScript::Object::DynamicSignal &currSig = *s;
+ COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
+#endif
+ }
+ seenSignals.insert(signalName);
+
+ cache->appendSignal(signalName, flags, effectiveMethodIndex++,
+ paramCount?paramTypes.constData():0, names);
+ }
+
+
+ // Dynamic slots
+ const quint32 *functionIndex = obj->functionOffsetTable();
+ for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) {
+ const QV4::CompiledData::Function *s = unit->header.functionAt(*functionIndex);
+ int paramCount = s->nFormals;
+
+ quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
+
+ if (paramCount)
+ flags |= QQmlPropertyData::HasArguments;
+
+ QString slotName = stringAt(s->nameIndex);
+ if (seenSignals.contains(slotName)) {
+#if 0 // ###
+ const QQmlScript::Object::DynamicSlot &currSlot = *s;
+ COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+#endif
+ }
+ // Note: we don't append slotName to the seenSignals list, since we don't
+ // protect against overriding change signals or methods with properties.
+
+ const quint32 *formalsIndices = s->formalsTable();
+ QList<QByteArray> parameterNames;
+ parameterNames.reserve(paramCount);
+ for (int i = 0; i < paramCount; ++i)
+ parameterNames << stringAt(formalsIndices[i]).toUtf8();
+
+ cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
+ }
+
+
+ // Dynamic properties (except var and aliases)
+ int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
+ /* const QV4::CompiledData::Property* */ p = obj->propertyTable();
+ for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
+
+ if (p->type == QV4::CompiledData::Property::Alias ||
+ p->type == QV4::CompiledData::Property::Var)
+ continue;
+
+ int propertyType = 0;
+ int vmePropertyType = 0;
+ quint32 propertyFlags = 0;
+
+ if (p->type < builtinTypeCount) {
+ propertyType = builtinTypes[p->type].metaType;
+ vmePropertyType = propertyType;
+
+ if (p->type == QV4::CompiledData::Property::Variant)
+ propertyFlags |= QQmlPropertyData::IsQVariant;
+ } else {
+ Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
+ p->type == QV4::CompiledData::Property::Custom);
+
+ QQmlType *qmltype = 0;
+ if (!imports.resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0))
+ COMPILE_EXCEPTION(p, tr("Invalid property type"));
+
+ Q_ASSERT(qmltype);
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = QQmlEnginePrivate::get(engine)->typeLoader.getType(qmltype->sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ QQmlCompiledData *data = tdata->compiledData();
+
+ if (p->type == QV4::CompiledData::Property::Custom) {
+ propertyType = data->metaTypeId;
+ vmePropertyType = QMetaType::QObjectStar;
+ } else {
+ propertyType = data->listMetaTypeId;
+ vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
+ }
+
+ tdata->release();
+ } else {
+ if (p->type == QV4::CompiledData::Property::Custom) {
+ propertyType = qmltype->typeId();
+ vmePropertyType = QMetaType::QObjectStar;
+ } else {
+ propertyType = qmltype->qListTypeId();
+ vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
+ }
+ }
+
+ if (p->type == QV4::CompiledData::Property::Custom)
+ propertyFlags |= QQmlPropertyData::IsQObjectDerived;
+ else
+ propertyFlags |= QQmlPropertyData::IsQList;
+ }
+
+ if ((!p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
+ propertyFlags |= QQmlPropertyData::IsWritable;
+
+
+ QString propertyName = stringAt(p->nameIndex);
+ if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
+ cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ propertyType, effectiveSignalIndex);
+
+ effectiveSignalIndex++;
+
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
+ vmd->propertyCount++;
+ }
+
+ // Now do var properties
+ /* const QV4::CompiledData::Property* */ p = obj->propertyTable();
+ for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
+
+ if (p->type != QV4::CompiledData::Property::Var)
+ continue;
+
+ quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
+ if (!p->flags & QV4::CompiledData::Property::IsReadOnly)
+ propertyFlags |= QQmlPropertyData::IsWritable;
+
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
+ vmd->propertyCount++;
+ ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
+
+ QString propertyName = stringAt(p->nameIndex);
+ if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
+ cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ QMetaType::QVariant, effectiveSignalIndex);
+
+ effectiveSignalIndex++;
+ }
+
+ // Alias property count. Actual data is setup in buildDynamicMetaAliases
+ ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
+
+ // Dynamic slot data - comes after the property data
+ /*const quint32* */functionIndex = obj->functionOffsetTable();
+ for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) {
+ const QV4::CompiledData::Function *s = unit->header.functionAt(*functionIndex);
+
+ VMD::MethodData methodData = { int(s->nFormals),
+ /* body offset*/0,
+ /* body length*/0,
+ /* s->location.start.line */0 }; // ###
+
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
+ vmd->methodCount++;
+ md = methodData;
+ }
+
+ return true;
+}
+
+QVariant QmlObjectCreator::variantForBinding(int expectedMetaType, const QV4::CompiledData::Binding *binding) const
+{
+ QVariant result;
+
+ switch (expectedMetaType) {
+ case QMetaType::QString:
+ result = valueAsString(&binding->value);
+ break;
+ case QMetaType::Bool:
+ result = valueAsBoolean(&binding->value);
+ break;
+ case QMetaType::Double:
+ result = valueAsNumber(&binding->value);
+ break;
+ case QMetaType::Int:
+ result = (int)valueAsNumber(&binding->value);
+ break;
+ case QVariant::Color: {
+ bool ok = false;
+ result = QQmlStringConverters::colorFromString(valueAsString(&binding->value), &ok);
+ if (!ok) {
+ // ### compile error
+ }
+ break;
+ }
+ default:
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(expectedMetaType);
+ if (converter) {
+ result = converter(valueAsString(&binding->value));
+ } else {
+ if (expectedMetaType == QMetaType::QVariant)
+ result = QVariant();
+ else
+ result = QVariant(expectedMetaType, (void*)0);
+ }
+ break;
+ }
+ return result;
+}
+
+QString QmlObjectCreator::valueAsString(const QV4::CompiledData::Value *value) const
+{
+ switch (value->type) {
+ case QV4::CompiledData::Value::Type_Script:
+ case QV4::CompiledData::Value::Type_String:
+ return stringAt(value->stringIndex);
+ case QV4::CompiledData::Value::Type_Boolean:
+ return value->b ? QStringLiteral("true") : QStringLiteral("false");
+ case QV4::CompiledData::Value::Type_Number:
+ return QString::number(value->d);
+ case QV4::CompiledData::Value::Type_Invalid:
+ return QString();
+ default:
+ break;
+ }
+ return QString();
+}
+
+double QmlObjectCreator::valueAsNumber(const QV4::CompiledData::Value *value)
+{
+ if (value->type == QV4::CompiledData::Value::Type_Number)
+ return value->d;
+ return 0.0;
+}
+
+bool QmlObjectCreator::valueAsBoolean(const QV4::CompiledData::Value *value)
+{
+ if (value->type == QV4::CompiledData::Value::Type_Boolean)
+ return value->b;
+ return false;
+}
+
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
new file mode 100644
index 0000000000..6a2b28c35d
--- /dev/null
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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 QQMLOBJECTCREATOR_P_H
+#define QQMLOBJECTCREATOR_P_H
+
+#include <private/qqmlimport_p.h>
+#include <private/qqmltypenamecache_p.h>
+#include <private/qv4compileddata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlAbstractBinding;
+
+namespace QtQml {
+
+struct Q_QML_EXPORT QmlObjectCreator
+{
+ QmlObjectCreator(QQmlEngine *engine,
+ // extra data/output stored in these two
+ QQmlContextData *contextData,
+ QQmlCompiledData *runtimeData);
+
+ QObject *create(QObject *parent = 0)
+ { return create(unit->indexOfRootObject); }
+ QObject *create(int index, QObject *parent = 0);
+
+ QList<QQmlError> errors;
+
+ bool createVMEMetaObjectAndPropertyCache(const QV4::CompiledData::Object *obj, QQmlPropertyCache *baseTypeCache, QQmlPropertyCache **cache, QByteArray *vmeMetaObjectData) const;
+private:
+ QString stringAt(int idx) const { return unit->header.stringAt(idx); }
+
+ QVector<QQmlAbstractBinding *> setupBindings(const QV4::CompiledData::Object *obj, QV4::Object *qmlGlobal);
+ void setupFunctions(const QV4::CompiledData::Object *obj, QV4::Object *qmlGlobal);
+
+ QVariant variantForBinding(int expectedMetaType, const QV4::CompiledData::Binding *binding) const;
+
+ QString valueAsString(const QV4::CompiledData::Value *value) const;
+ static double valueAsNumber(const QV4::CompiledData::Value *value);
+ static bool valueAsBoolean(const QV4::CompiledData::Value *value);
+
+ QQmlEngine *engine;
+ const QV4::CompiledData::QmlUnit *unit;
+ const QV4::CompiledData::CompilationUnit *jsUnit;
+ QQmlContextData *context;
+ QQmlTypeNameCache *typeNameCache;
+ QQmlCompiledData *runtimeData;
+ QQmlImports imports;
+
+ QObject *_object;
+ QQmlData *_ddata;
+ QQmlPropertyCache *_propertyCache;
+};
+
+} // end namespace QtQml
+
+QT_END_NAMESPACE
+
+#endif // QQMLOBJECTCREATOR_P_H
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 21fee28b02..0fd9252754 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -66,6 +66,10 @@
QT_BEGIN_NAMESPACE
+namespace QtQml {
+struct QmlObjectCreator;
+}
+
class QV8Engine;
class QMetaProperty;
class QQmlEngine;
@@ -339,6 +343,7 @@ protected:
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
+ friend struct QtQml::QmlObjectCreator;
inline QQmlPropertyCache *copy(int reserve);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 3531e89779..cd57704771 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1900,6 +1900,7 @@ QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
: QQmlTypeLoader::Blob(url, QmlFile, manager),
m_typesResolved(false), m_compiledData(0), m_implicitImport(0), m_implicitImportLoaded(false)
{
+ m_useNewCompiler = QQmlEnginePrivate::get(manager->engine())->useNewCompiler;
}
QQmlTypeData::~QQmlTypeData()
@@ -2031,9 +2032,17 @@ void QQmlTypeData::dataReceived(const Data &data)
if (data.isFile()) preparseData = data.asFile()->metaData(QLatin1String("qml:preparse"));
- if (!scriptParser.parse(code, preparseData, finalUrl(), finalUrlString())) {
- setError(scriptParser.errors());
- return;
+ if (m_useNewCompiler) {
+ QQmlCodeGenerator compiler;
+ if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), &parsedQML)) {
+ setError(compiler.errors);
+ return;
+ }
+ } else {
+ if (!scriptParser.parse(code, preparseData, finalUrl(), finalUrlString())) {
+ setError(scriptParser.errors());
+ return;
+ }
}
m_imports.setBaseUrl(finalUrl(), finalUrlString());
@@ -2063,7 +2072,34 @@ void QQmlTypeData::dataReceived(const Data &data)
QList<QQmlError> errors;
- foreach (const QQmlScript::Import &import, scriptParser.imports()) {
+ // ### convert to use new data structure once old compiler is gone.
+ QList<QQmlScript::Import> imports;
+ if (m_useNewCompiler) {
+ imports.reserve(parsedQML.imports.size());
+ foreach (QV4::CompiledData::Import *i, parsedQML.imports) {
+ QQmlScript::Import import;
+ import.uri = parsedQML.stringAt(i->uriIndex);
+ import.qualifier = parsedQML.stringAt(i->qualifierIndex);
+ import.majorVersion = i->majorVersion;
+ import.minorVersion = i->minorVersion;
+ import.location.start.line = i->location.line;
+ import.location.start.column = i->location.column;
+
+ switch (i->type) {
+ case QV4::CompiledData::Import::ImportFile: import.type = QQmlScript::Import::File; break;
+ case QV4::CompiledData::Import::ImportLibrary: import.type = QQmlScript::Import::Library; break;
+ case QV4::CompiledData::Import::ImportScript: import.type = QQmlScript::Import::Script; break;
+ default: break;
+ }
+
+
+ imports << import;
+ }
+ } else {
+ imports = scriptParser.imports();
+ }
+
+ foreach (const QQmlScript::Import &import, imports) {
if (!addImport(import, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
@@ -2124,11 +2160,36 @@ void QQmlTypeData::compile()
QQmlCompilingProfiler prof(m_compiledData->name);
- QQmlCompiler compiler(&scriptParser._pool);
- if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
- setError(compiler.errors());
- m_compiledData->release();
- m_compiledData = 0;
+ if (m_useNewCompiler) {
+ JSCodeGen jsCodeGen;
+ jsCodeGen.generateJSCodeForFunctionsAndBindings(finalUrlString(), &parsedQML);
+
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
+
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &parsedQML.jsModule, &parsedQML.jsGenerator));
+ isel->setUseFastLookups(false);
+ QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
+
+ QmlUnitGenerator qmlGenerator;
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(parsedQML);
+
+ 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
+ } else {
+ QQmlCompiler compiler(&scriptParser._pool);
+ if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
+ 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 abe545fc8f..9e71bab7b0 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -68,6 +68,7 @@
#include <private/qqmlbundle_p.h>
#include <private/qflagpointer_p.h>
#include <private/qqmlabstracturlinterceptor_p.h>
+#include <private/qqmlcodegenerator_p.h>
#include <private/qv4value_p.h>
#include <private/qv4script_p.h>
@@ -446,7 +447,11 @@ private:
virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
+ // --- old compiler
QQmlScript::Parser scriptParser;
+ // --- new compiler
+ QtQml::ParsedQML parsedQML;
+ // ---
QList<ScriptReference> m_scripts;
@@ -454,6 +459,7 @@ private:
QList<TypeReference> m_types;
bool m_typesResolved:1;
+ bool m_useNewCompiler:1;
QQmlCompiledData *m_compiledData;