aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;