aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-20 16:47:57 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2013-09-20 16:48:32 +0200
commit57919fe200c0ecbd4cf1873ed2c6c95732c2dd3b (patch)
tree048fa6b5f80987b7765252204b77bc3618bbe33f
parent3ea14e269bec15db8a95dc4b610a5f063a67e1a2 (diff)
parent3123a22ae66016a0d9cd600dbb6f636fd29fc312 (diff)
Merge branch 'wip/v4' of qtdeclarative into dev
This brings in the infrastructure for the new compilation of QML and JS in the loader thread and the new VME replacement for creating objects in the GUI thread. Change-Id: Ib8127c10f5cb3ad238e57469723d031ab765a79b
-rw-r--r--src/3rdparty/masm/stubs/ExecutableAllocator.h2
-rw-r--r--src/qml/compiler/compiler.pri6
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp1375
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h358
-rw-r--r--src/qml/compiler/qv4codegen.cpp4
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp46
-rw-r--r--src/qml/compiler/qv4compileddata_p.h202
-rw-r--r--src/qml/compiler/qv4compiler.cpp20
-rw-r--r--src/qml/compiler/qv4compiler_p.h11
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp7
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h6
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp7
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h6
-rw-r--r--src/qml/compiler/qv4isel_p.cpp20
-rw-r--r--src/qml/compiler/qv4isel_p.h20
-rw-r--r--src/qml/compiler/qv4jsir.cpp4
-rw-r--r--src/qml/compiler/qv4jsir_p.h6
-rw-r--r--src/qml/jsruntime/qv4context.cpp10
-rw-r--r--src/qml/jsruntime/qv4engine.cpp6
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp27
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h8
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4script.cpp98
-rw-r--r--src/qml/jsruntime/qv4script_p.h18
-rw-r--r--src/qml/qml/qml.pri6
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h3
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp13
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h3
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp17
-rw-r--r--src/qml/qml/qqmlcompiler_p.h22
-rw-r--r--src/qml/qml/qqmlcomponent.cpp36
-rw-r--r--src/qml/qml/qqmlcomponent.h1
-rw-r--r--src/qml/qml/qqmlcomponent_p.h16
-rw-r--r--src/qml/qml/qqmlengine.cpp5
-rw-r--r--src/qml/qml/qqmlengine_p.h6
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp1575
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h160
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h3
-rw-r--r--src/qml/qml/qqmltypeloader.cpp287
-rw-r--r--src/qml/qml/qqmltypeloader_p.h28
-rw-r--r--tools/qmlscene/main.cpp4
43 files changed, 4269 insertions, 189 deletions
diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h
index 4e3be7ca4a..a8f54df39f 100644
--- a/src/3rdparty/masm/stubs/ExecutableAllocator.h
+++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h
@@ -67,7 +67,7 @@ struct ExecutableMemoryHandle : public RefCounted<ExecutableMemoryHandle> {
}
~ExecutableMemoryHandle()
{
- m_allocator->free(m_allocation);
+ m_allocation->deallocate(m_allocator);
}
inline void shrink(size_t) {
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..381f5bfec9
--- /dev/null
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -0,0 +1,1375 @@
+/****************************************************************************
+**
+** 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 <private/qqmlcompiler_p.h>
+#include <QCoreApplication>
+
+QT_USE_NAMESPACE
+
+using namespace QtQml;
+
+#define COMPILE_EXCEPTION(location, desc) \
+ { \
+ recordError(location, desc); \
+ return false; \
+ }
+
+void QmlObject::dump(DebugStream &out)
+{
+ out << inheritedTypeNameIndex << " {" << endl;
+ out.indent++;
+
+ out.indent--;
+ out << "}" << endl;
+}
+
+QStringList Signal::parameterStringList(const QStringList &stringPool) const
+{
+ QStringList result;
+ result.reserve(parameters->count);
+ for (SignalParameter *param = parameters->first; param; param = param->next)
+ result << stringPool.at(param->nameIndex);
+ return result;
+}
+
+QQmlCodeGenerator::QQmlCodeGenerator()
+ : _object(0)
+ , jsGenerator(0)
+{
+}
+
+bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output)
+{
+ this->url = url;
+ 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;
+ output->program = program;
+
+ qSwap(_imports, output->imports);
+ qSwap(_objects, output->objects);
+ qSwap(_functions, output->functions);
+ qSwap(_typeReferences, output->typeReferences);
+ this->pool = output->jsParserEngine.pool();
+ this->jsGenerator = &output->jsGenerator;
+
+ emptyStringIndex = registerString(QString());
+
+ 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;
+ }
+
+ // Reserve space for pseudo context-scope function
+ _functions << program;
+
+ AST::UiObjectDefinition *rootObject = AST::cast<AST::UiObjectDefinition*>(program->members->member);
+ Q_ASSERT(rootObject);
+ output->indexOfRootObject = defineQMLObject(rootObject);
+
+ collectTypeReferences();
+
+ qSwap(_imports, output->imports);
+ qSwap(_objects, output->objects);
+ qSwap(_functions, output->functions);
+ qSwap(_typeReferences, output->typeReferences);
+ return errors.isEmpty();
+}
+
+bool QQmlCodeGenerator::isSignalPropertyName(const QString &name)
+{
+ if (name.length() < 3) return false;
+ if (!name.startsWith(QStringLiteral("on"))) return false;
+ int ns = name.length();
+ for (int i = 2; i < ns; ++i) {
+ const QChar curr = name.at(i);
+ if (curr.unicode() == '_') continue;
+ if (curr.isUpper()) return true;
+ return false;
+ }
+ return false; // consists solely of underscores - invalid.
+}
+
+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)
+{
+ // The grammar can't distinguish between two different definitions here:
+ // Item { ... }
+ // versus
+ // font { ... }
+ // The former is a new binding with no property name and "Item" as type name,
+ // and the latter is a binding to the font property with no type name but
+ // only initializer.
+
+ AST::UiQualifiedId *lastId = node->qualifiedTypeNameId;
+ while (lastId->next)
+ lastId = lastId->next;
+ bool isType = lastId->name.unicode()->isUpper();
+ if (isType) {
+ int idx = defineQMLObject(node);
+ appendBinding(AST::SourceLocation(), emptyStringIndex, idx);
+ } else {
+ int idx = defineQMLObject(/*qualfied type name id*/0, node->initializer);
+ appendBinding(node->qualifiedTypeNameId, idx);
+ }
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiObjectBinding *node)
+{
+ int idx = defineQMLObject(node->qualifiedTypeNameId, node->initializer);
+ appendBinding(node->qualifiedId, idx);
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiScriptBinding *node)
+{
+ appendBinding(node->qualifiedId, node->statement);
+ return false;
+}
+
+bool QQmlCodeGenerator::visit(AST::UiArrayBinding *node)
+{
+ QmlObject *object = 0;
+ AST::UiQualifiedId *name = node->qualifiedId;
+ if (!resolveQualifiedId(&name, &object))
+ return false;
+
+ qSwap(_object, object);
+
+ AST::UiArrayMemberList *member = node->members;
+ while (member) {
+ AST::UiObjectDefinition *def = AST::cast<AST::UiObjectDefinition*>(member->member);
+
+ int idx = defineQMLObject(def);
+ appendBinding(name->identifierToken, registerString(name->name.toString()), idx, /*isListItem*/ true);
+
+ member = member->next;
+ }
+
+ qSwap(_object, object);
+ return false;
+}
+
+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);
+}
+
+bool QQmlCodeGenerator::sanityCheckFunctionNames()
+{
+ QSet<QString> functionNames;
+ for (Function *f = _object->functions->first; f; f = f->next) {
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index));
+ Q_ASSERT(function);
+ QString name = function->name.toString();
+ if (functionNames.contains(name))
+ COMPILE_EXCEPTION(function->identifierToken, tr("Duplicate method name"));
+ functionNames.insert(name);
+ if (_signalNames.contains(name))
+ COMPILE_EXCEPTION(function->identifierToken, tr("Duplicate method name"));
+
+ if (name.at(0).isUpper())
+ COMPILE_EXCEPTION(function->identifierToken, tr("Method names cannot begin with an upper case letter"));
+#if 0 // ###
+ if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name.toString()))
+ COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
+#endif
+ }
+ return true;
+}
+
+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));
+
+ AST::SourceLocation loc;
+ if (qualifiedTypeNameId)
+ loc = qualifiedTypeNameId->firstSourceLocation();
+ _object->location.line = loc.startLine;
+ _object->location.column = loc.startColumn;
+
+ _object->idIndex = emptyStringIndex;
+ _object->indexOfDefaultProperty = -1;
+ _object->properties = New<PoolList<QmlProperty> >();
+ _object->qmlSignals = New<PoolList<Signal> >();
+ _object->bindings = New<PoolList<Binding> >();
+ _object->functions = New<PoolList<Function> >();
+
+ QSet<QString> propertyNames;
+ qSwap(_propertyNames, propertyNames);
+ QSet<QString> signalNames;
+ qSwap(_signalNames, signalNames);
+
+ accept(initializer);
+
+ sanityCheckFunctionNames();
+
+ qSwap(_propertyNames, propertyNames);
+ qSwap(_signalNames, signalNames);
+ 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 = emptyStringIndex;
+
+ // 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;
+}
+
+static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
+{
+ if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
+ QString name =
+ static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
+ return QStringList() << name;
+ } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
+ QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
+
+ QStringList rv = astNodeToStringList(expr->base);
+ if (rv.isEmpty())
+ return rv;
+ rv.append(expr->name.toString());
+ return rv;
+ }
+ return QStringList();
+}
+
+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>();
+ QString signalName = node->name.toString();
+ signal->nameIndex = registerString(signalName);
+
+ AST::SourceLocation loc = node->firstSourceLocation();
+ signal->location.line = loc.startLine;
+ signal->location.column = loc.startColumn;
+
+ 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 = emptyStringIndex;
+ }
+
+ param->nameIndex = registerString(p->name.toString());
+ param->location.line = p->identifierToken.startLine;
+ param->location.column = p->identifierToken.startColumn;
+ signal->parameters->append(param);
+ p = p->next;
+ }
+
+ if (_signalNames.contains(signalName))
+ COMPILE_EXCEPTION(node->identifierToken, tr("Duplicate signal name"));
+ _signalNames.insert(signalName);
+
+ if (signalName.at(0).isUpper())
+ COMPILE_EXCEPTION(node->identifierToken, tr("Signal names cannot begin with an upper case letter"));
+
+#if 0 // ### cannot access identifier table from separate thread
+ if (enginePrivate->v8engine()->illegalNames().contains(currSig.name.toString()))
+ COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
+#endif
+
+ _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 = emptyStringIndex;
+
+ property->nameIndex = registerString(name.toString());
+
+ AST::SourceLocation loc = node->firstSourceLocation();
+ property->location.line = loc.startLine;
+ property->location.column = loc.startColumn;
+
+ property->aliasPropertyValueIndex = emptyStringIndex;
+
+ if (type == QV4::CompiledData::Property::Alias) {
+ if (!node->statement && !node->binding)
+ COMPILE_EXCEPTION(loc, tr("No property alias location"));
+
+ QStringList alias;
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node->statement))
+ alias = astNodeToStringList(stmt->expression);
+
+ if (node->binding || alias.isEmpty())
+ COMPILE_EXCEPTION(loc, tr("Invalid alias location"));
+
+ if (alias.count() < 1 || alias.count() > 3)
+ COMPILE_EXCEPTION(loc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+
+ property->aliasIdValueIndex = registerString(alias.first());
+
+ QString propertyValue = alias.value(1);
+ if (alias.count() == 3) {
+ propertyValue += QLatin1Char('.');
+ propertyValue += alias.at(2);
+ }
+ property->aliasPropertyValueIndex = registerString(propertyValue);
+ } else if (node->statement)
+ appendBinding(node->identifierToken, 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 {})
+ 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->type = QV4::CompiledData::Binding::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->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = registerString(lit->value.toString());
+ } else if (expr->kind == AST::Node::Kind_TrueLiteral) {
+ binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->value.b = true;
+ } else if (expr->kind == AST::Node::Kind_FalseLiteral) {
+ binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->value.b = false;
+ } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) {
+ binding->type = QV4::CompiledData::Binding::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->type = QV4::CompiledData::Binding::Type_Number;
+ binding->value.d = -lit->value;
+ }
+ }
+ }
+ }
+
+ // Do binding instead
+ if (binding->type == QV4::CompiledData::Binding::Type_Invalid) {
+ binding->type = QV4::CompiledData::Binding::Type_Script;
+ _functions << statement;
+ binding->value.compiledScriptIndex = _functions.size() - 1;
+ binding->stringIndex = registerString(asStringRef(statement).toString());
+ }
+}
+
+void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, AST::Statement *value)
+{
+ QmlObject *object = 0;
+ if (!resolveQualifiedId(&name, &object))
+ return;
+ qSwap(_object, object);
+ appendBinding(name->identifierToken, registerString(name->name.toString()), value);
+ qSwap(_object, object);
+}
+
+void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, int objectIndex)
+{
+ QmlObject *object = 0;
+ if (!resolveQualifiedId(&name, &object))
+ return;
+ qSwap(_object, object);
+ appendBinding(name->identifierToken, registerString(name->name.toString()), objectIndex);
+ qSwap(_object, object);
+}
+
+void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value)
+{
+ if (!sanityCheckPropertyName(nameLocation, propertyNameIndex))
+ return;
+
+ if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
+ setId(value);
+ return;
+ }
+
+ Binding *binding = New<Binding>();
+ binding->propertyNameIndex = propertyNameIndex;
+ binding->location.line = nameLocation.startLine;
+ binding->location.column = nameLocation.startColumn;
+ binding->flags = 0;
+ setBindingValue(binding, value);
+ _object->bindings->append(binding);
+}
+
+void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem)
+{
+ if (!sanityCheckPropertyName(nameLocation, propertyNameIndex, isListItem))
+ return;
+
+ if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
+ recordError(nameLocation, tr("Invalid component id specification"));
+ return;
+ }
+
+ Binding *binding = New<Binding>();
+ binding->propertyNameIndex = propertyNameIndex;
+ binding->location.line = nameLocation.startLine;
+ binding->location.column = nameLocation.startColumn;
+ binding->flags = 0;
+ binding->type = QV4::CompiledData::Binding::Type_Object;
+ binding->value.objectIndex = objectIndex;
+ _object->bindings->append(binding);
+}
+
+bool QQmlCodeGenerator::setId(AST::Statement *value)
+{
+ AST::SourceLocation loc = value->firstSourceLocation();
+ QStringRef str;
+
+ AST::Node *node = value;
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node)) {
+ if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(stmt->expression))
+ str = lit->value;
+ else
+ node = stmt->expression;
+ }
+
+ if (str.isEmpty())
+ str = asStringRef(node);
+
+ if (str.isEmpty())
+ COMPILE_EXCEPTION(loc, tr( "Invalid empty ID"));
+
+ QChar ch = str.at(0);
+ if (ch.isLetter() && !ch.isLower())
+ COMPILE_EXCEPTION(loc, tr( "IDs cannot start with an uppercase letter"));
+
+ QChar u(QLatin1Char('_'));
+ if (!ch.isLetter() && ch != u)
+ COMPILE_EXCEPTION(loc, tr( "IDs must start with a letter or underscore"));
+
+ for (int ii = 1; ii < str.count(); ++ii) {
+ ch = str.at(ii);
+ if (!ch.isLetterOrNumber() && ch != u)
+ COMPILE_EXCEPTION(loc, tr( "IDs must contain only letters, numbers, and underscores"));
+ }
+
+#if 0 // ###
+ if (enginePrivate->v8engine()->illegalNames().contains(str))
+ COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
+#endif
+
+ _object->idIndex = registerString(str.toString());
+ _object->locationOfIdProperty.line = loc.startLine;
+ _object->locationOfIdProperty.column = loc.startColumn;
+
+ return true;
+}
+
+bool QQmlCodeGenerator::resolveQualifiedId(AST::UiQualifiedId **nameToResolve, QmlObject **object)
+{
+ AST::UiQualifiedId *name = *nameToResolve;
+
+ if (name->name == QStringLiteral("id") && name->next)
+ COMPILE_EXCEPTION(name->identifierToken, tr( "Invalid use of id property"));
+
+ *object = _object;
+ while (name->next) {
+ Binding *binding = New<Binding>();
+ binding->propertyNameIndex = registerString(name->name.toString());
+ binding->location.line = name->identifierToken.startLine;
+ binding->location.column = name->identifierToken.startColumn;
+ binding->flags = 0;
+
+ if (name->name.unicode()->isUpper())
+ binding->type = QV4::CompiledData::Binding::Type_AttachedProperty;
+ else
+ binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+
+ int objIndex = defineQMLObject(0, 0);
+ binding->value.objectIndex = objIndex;
+
+ (*object)->bindings->append(binding);
+ *object = _objects[objIndex];
+
+ name = name->next;
+ }
+ *nameToResolve = name;
+ return true;
+}
+
+bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItem)
+{
+ const QString &name = jsGenerator->strings.at(nameIndex);
+ if (name.isEmpty())
+ return true;
+
+ // List items are implement by multiple bindings to the same name, so allow duplicates.
+ if (!isListItem) {
+ if (_propertyNames.contains(name))
+ COMPILE_EXCEPTION(nameLocation, tr("Duplicate property name"));
+
+ _propertyNames.insert(name);
+ }
+
+ if (name.at(0).isUpper())
+ COMPILE_EXCEPTION(nameLocation, tr("Property names cannot begin with an upper case letter"));
+
+#if 0 // ### how to check against illegalNames when in separate thread?
+ if (enginePrivate->v8engine()->illegalNames().contains(prop.name.toString())) {
+ COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
+ prop.nameLocation.column,
+ tr("Illegal property name"));
+ }
+#endif
+
+ return true;
+}
+
+void QQmlCodeGenerator::recordError(const AST::SourceLocation &location, const QString &description)
+{
+ QQmlError error;
+ error.setUrl(url);
+ error.setLine(location.startLine);
+ error.setColumn(location.startColumn);
+ error.setDescription(description);
+ errors << error;
+}
+
+void QQmlCodeGenerator::collectTypeReferences()
+{
+ foreach (QmlObject *obj, _objects) {
+ if (!stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ _typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
+
+ for (QmlProperty *prop = obj->properties->first; prop; prop = prop->next) {
+ if (prop->type >= QV4::CompiledData::Property::Custom)
+ _typeReferences.add(prop->customTypeNameIndex, prop->location);
+ }
+
+ for (Signal *sig = obj->qmlSignals->first; sig; sig = sig->next)
+ for (SignalParameter *param = sig->parameters->first; param; param = param->next)
+ if (!stringAt(param->customTypeNameIndex).isEmpty())
+ _typeReferences.add(param->customTypeNameIndex, param->location);
+
+ for (Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ _typeReferences.add(binding->propertyNameIndex, binding->location);
+ }
+ }
+}
+
+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;
+ objectToWrite->location = o->location;
+ objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
+
+ 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->location = s->location;
+ 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);
+
+ QmlScanner scan(this, output->code);
+ scan.begin(output->program);
+ foreach (AST::Node *node, output->functions) {
+ if (node == output->program)
+ continue;
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
+
+ scan.enterEnvironment(node);
+ scan(function ? function->body : node);
+ scan.leaveEnvironment();
+ }
+ scan.end();
+
+ _env = 0;
+ _function = defineFunction(QString("context scope"), output->program, 0, 0, QmlBinding);
+
+ foreach (AST::Node *node, output->functions) {
+ if (node == output->program)
+ continue;
+
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
+
+ QString name;
+ if (function)
+ name = function->name.toString();
+ else
+ name = QStringLiteral("%qml-expression-entry");
+
+ AST::SourceElements *body;
+ if (function)
+ body = function->body ? function->body->elements : 0;
+ else {
+ // Synthesize source elements.
+ QQmlJS::MemoryPool *pool = output->jsParserEngine.pool();
+ AST::SourceElement *element = new (pool) AST::StatementSourceElement(static_cast<AST::Statement*>(node));
+ body = new (output->jsParserEngine.pool()) AST::SourceElements(element);
+ body = body->finish();
+ }
+
+ defineFunction(name, node,
+ function ? function->formals : 0,
+ body, function ? FunctionCode : QmlBinding);
+
+ }
+
+ qDeleteAll(_envMap);
+ _envMap.clear();
+}
+
+
+void JSCodeGen::QmlScanner::begin(AST::Node *rootNode)
+{
+ enterEnvironment(0);
+ enterFunction(rootNode, "context scope", 0, 0, 0, /*isExpression*/false);
+}
+
+void JSCodeGen::QmlScanner::end()
+{
+ leaveEnvironment();
+}
+
+SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate, ParsedQML *parsedQML,
+ QQmlCompiledData *unit)
+ : enginePrivate(enginePrivate)
+ , parsedQML(parsedQML)
+ , unit(unit)
+{
+}
+
+bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
+{
+ foreach (QmlObject *obj, parsedQML->objects) {
+ QString elementName = stringAt(obj->inheritedTypeNameIndex);
+ if (elementName.isEmpty())
+ continue;
+ QQmlPropertyCache *cache = unit->resolvedTypes[obj->inheritedTypeNameIndex].createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
+ return false;
+ }
+ return true;
+}
+
+bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(QmlObject *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
+{
+ // map from signal name defined in qml itself to list of parameters
+ QHash<QString, QStringList> customSignals;
+
+ for (Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ QString propertyName = stringAt(binding->propertyNameIndex);
+ // Attached property?
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ QmlObject *attachedObj = parsedQML->objects[binding->value.objectIndex];
+ QQmlType *type = unit->resolvedTypes.value(binding->propertyNameIndex).type;
+ const QMetaObject *attachedType = type ? type->attachedPropertiesType() : 0;
+ if (!attachedType)
+ COMPILE_EXCEPTION(binding->location, tr("Non-existent attached object"));
+ QQmlPropertyCache *cache = enginePrivate->cache(attachedType);
+ if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache))
+ return false;
+ continue;
+ }
+
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ if (!QQmlCodeGenerator::isSignalPropertyName(propertyName))
+ continue;
+
+ PropertyResolver resolver(propertyCache);
+
+ Q_ASSERT(propertyName.startsWith(QStringLiteral("on")));
+ propertyName.remove(0, 2);
+
+ // Note that the property name could start with any alpha or '_' or '$' character,
+ // so we need to do the lower-casing of the first alpha character.
+ for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) {
+ if (propertyName.at(firstAlphaIndex).isUpper()) {
+ propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower();
+ break;
+ }
+ }
+
+ QList<QString> parameters;
+
+ bool notInRevision = false;
+ QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
+ if (signal) {
+ int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex);
+ foreach (const QByteArray &param, propertyCache->signalParameterNames(sigIndex))
+ parameters << QString::fromUtf8(param);
+ } else {
+ if (notInRevision) {
+ // Try assinging it as a property later
+ if (resolver.property(propertyName, /*notInRevision ptr*/0))
+ continue;
+
+ const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
+
+ const QQmlType *type = unit->resolvedTypes.value(obj->inheritedTypeNameIndex).type;
+ if (type) {
+ COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion()));
+ } else {
+ COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
+ }
+ }
+
+ // Try to look up the signal parameter names in the object itself
+
+ // build cache if necessary
+ if (customSignals.isEmpty()) {
+ for (Signal *signal = obj->qmlSignals->first; signal; signal = signal->next) {
+ const QString &signalName = stringAt(signal->nameIndex);
+ customSignals.insert(signalName, signal->parameterStringList(parsedQML->jsGenerator.strings));
+ }
+ }
+
+ QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName);
+ if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) {
+ QString alternateName = propertyName.mid(0, propertyName.length() - strlen("Changed"));
+ entry = customSignals.find(alternateName);
+ }
+
+ if (entry == customSignals.constEnd()) {
+ // Can't find even a custom signal, then just don't do anything and try
+ // keeping the binding as a regular property assignment.
+ continue;
+ }
+
+ parameters = entry.value();
+ }
+
+ QQmlJS::Engine &jsEngine = parsedQML->jsParserEngine;
+ QQmlJS::MemoryPool *pool = jsEngine.pool();
+
+ AST::FormalParameterList *paramList = 0;
+ foreach (const QString &param, parameters) {
+ QStringRef paramNameRef = jsEngine.newStringRef(param);
+
+ if (paramList)
+ paramList = new (pool) AST::FormalParameterList(paramList, paramNameRef);
+ else
+ paramList = new (pool) AST::FormalParameterList(paramNameRef);
+ }
+
+ if (paramList)
+ paramList = paramList->finish();
+
+ AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex]);
+ AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement);
+ AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement);
+ elements = elements->finish();
+
+ AST::FunctionBody *body = new (pool) AST::FunctionBody(elements);
+
+ AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine.newStringRef(propertyName), paramList, body);
+
+ parsedQML->functions[binding->value.compiledScriptIndex] = functionDeclaration;
+ binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
+ binding->propertyNameIndex = parsedQML->jsGenerator.registerString(propertyName);
+ }
+ return true;
+}
+
+void SignalHandlerConverter::recordError(const QV4::CompiledData::Location &location, const QString &description)
+{
+ QQmlError error;
+ error.setUrl(unit->url);
+ error.setLine(location.line);
+ error.setColumn(location.column);
+ error.setDescription(description);
+ errors << error;
+}
+
+QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision)
+{
+ if (notInRevision) *notInRevision = false;
+
+ QQmlPropertyData *d = cache->property(name, 0, 0);
+
+ // Find the first property
+ while (d && d->isFunction())
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return 0;
+ } else {
+ return d;
+ }
+}
+
+
+QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision)
+{
+ if (notInRevision) *notInRevision = false;
+
+ QQmlPropertyData *d = cache->property(name, 0, 0);
+ if (notInRevision) *notInRevision = false;
+
+ while (d && !(d->isFunction()))
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return 0;
+ } else if (d && d->isSignal()) {
+ return d;
+ }
+
+ if (name.endsWith(QStringLiteral("Changed"))) {
+ QString propName = name.mid(0, name.length() - strlen("Changed"));
+
+ d = property(propName, notInRevision);
+ if (d)
+ return cache->signal(d->notifyIndex);
+ }
+
+ return 0;
+}
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
new file mode 100644
index 0000000000..c3a3a8e4c3
--- /dev/null
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** 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>
+#include <QCoreApplication>
+
+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;
+ QV4::CompiledData::Location location;
+ PoolList<SignalParameter> *parameters;
+
+ QStringList parameterStringList(const QStringList &stringPool) const;
+
+ 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;
+
+ QV4::CompiledData::Location location;
+ QV4::CompiledData::Location locationOfIdProperty;
+
+ 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;
+ AST::UiProgram *program;
+ int indexOfRootObject;
+ QList<QmlObject*> objects;
+ QList<AST::Node*> functions; // FunctionDeclaration, Statement or Expression
+ QV4::Compiler::JSUnitGenerator jsGenerator;
+
+ QV4::CompiledData::TypeReferenceMap typeReferences;
+
+ 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
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
+public:
+ QQmlCodeGenerator();
+ bool generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output);
+
+ static bool isSignalPropertyName(const QString &name);
+
+ 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(AST::UiQualifiedId *name, AST::Statement *value);
+ void appendBinding(AST::UiQualifiedId *name, int objectIndex);
+ void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value);
+ void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem = false);
+
+ bool setId(AST::Statement *value);
+
+ // resolves qualified name (font.pixelSize for example) and returns the last name along
+ // with the object any right-hand-side of a binding should apply to.
+ bool resolveQualifiedId(AST::UiQualifiedId **nameToResolve, QmlObject **object);
+
+ bool sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItem = false);
+
+ void recordError(const AST::SourceLocation &location, const QString &description);
+
+ void collectTypeReferences();
+
+ 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(); }
+
+ QString stringAt(int index) const { return jsGenerator->strings.at(index); }
+
+ QList<QQmlError> errors;
+
+ QList<QV4::CompiledData::Import*> _imports;
+ QList<QmlObject*> _objects;
+ QList<AST::Node*> _functions;
+
+ QV4::CompiledData::TypeReferenceMap _typeReferences;
+
+ QmlObject *_object;
+ QSet<QString> _propertyNames;
+ QSet<QString> _signalNames;
+
+ QQmlJS::MemoryPool *pool;
+ QString sourceCode;
+ QUrl url;
+ QV4::Compiler::JSUnitGenerator *jsGenerator;
+ int emptyStringIndex;
+ bool sanityCheckFunctionNames();
+};
+
+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 PropertyResolver
+{
+ PropertyResolver(QQmlPropertyCache *cache)
+ : cache(cache)
+ {}
+
+ QQmlPropertyData *property(int index)
+ {
+ return cache->property(index);
+ }
+
+ QQmlPropertyData *property(const QString &name, bool *notInRevision = 0);
+
+ // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
+ QQmlPropertyData *signal(const QString &name, bool *notInRevision);
+
+ QQmlPropertyCache *cache;
+};
+
+// "Converts" signal expressions to full-fleged function declarations with
+// parameters taken from the signal declarations
+// It also updates the QV4::CompiledData::Binding objects to set the property name
+// to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag.
+struct SignalHandlerConverter
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
+public:
+ SignalHandlerConverter(QQmlEnginePrivate *enginePrivate, ParsedQML *parsedQML,
+ QQmlCompiledData *unit);
+
+ bool convertSignalHandlerExpressionsToFunctionDeclarations();
+
+ QList<QQmlError> errors;
+
+private:
+ bool convertSignalHandlerExpressionsToFunctionDeclarations(QmlObject *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
+
+ const QString &stringAt(int index) const { return parsedQML->jsGenerator.strings.at(index); }
+ void recordError(const QV4::CompiledData::Location &location, const QString &description);
+
+ QQmlEnginePrivate *enginePrivate;
+ ParsedQML *parsedQML;
+ QQmlCompiledData *unit;
+};
+
+struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
+{
+ JSCodeGen()
+ : QQmlJS::Codegen(/*strict mode*/false)
+ {}
+
+ void generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output);
+
+private:
+ struct QmlScanner : public ScanFunctions
+ {
+ QmlScanner(JSCodeGen *cg, const QString &sourceCode)
+ : ScanFunctions(cg, sourceCode)
+ , codeGen(cg)
+ {}
+
+ void begin(AST::Node *rootNode);
+ void end();
+
+ JSCodeGen *codeGen;
+ };
+
+ 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 4b2c0245a4..303d001246 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1767,6 +1767,10 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
function->isStrict = _env->isStrict;
function->isNamedExpression = _env->isNamedFunctionExpression;
+ AST::SourceLocation loc = ast->firstSourceLocation();
+ function->line = loc.startLine;
+ function->column = loc.startColumn;
+
if (function->usesArgumentsObject)
_env->enter("arguments", Environment::VariableDeclaration);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 2d2ca55f8d..3d5d92452b 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -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.cpp b/src/qml/compiler/qv4compileddata.cpp
index 74793d69fd..991fc922c3 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -65,13 +65,7 @@ namespace {
CompilationUnit::~CompilationUnit()
{
- engine->compilationUnits.erase(engine->compilationUnits.find(this));
- free(data);
- free(runtimeStrings);
- delete [] runtimeLookups;
- delete [] runtimeRegularExpressions;
- free(runtimeClasses);
- qDeleteAll(runtimeFunctions);
+ unlink();
}
QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
@@ -145,6 +139,26 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
return runtimeFunctions[data->indexOfRootFunction];
}
+void CompilationUnit::unlink()
+{
+ if (engine)
+ engine->compilationUnits.erase(engine->compilationUnits.find(this));
+ engine = 0;
+ if (ownsData)
+ free(data);
+ data = 0;
+ free(runtimeStrings);
+ runtimeStrings = 0;
+ delete [] runtimeLookups;
+ runtimeLookups = 0;
+ delete [] runtimeRegularExpressions;
+ runtimeRegularExpressions = 0;
+ free(runtimeClasses);
+ runtimeClasses = 0;
+ qDeleteAll(runtimeFunctions);
+ runtimeFunctions.clear();
+}
+
void CompilationUnit::markObjects()
{
for (int i = 0; i < data->stringTableSize; ++i)
@@ -155,6 +169,24 @@ void CompilationUnit::markObjects()
runtimeFunctions[i]->mark();
}
+QString Binding::valueAsString(const Unit *unit) const
+{
+ switch (type) {
+ case Type_Script:
+ case Type_String:
+ return unit->stringAt(stringIndex);
+ case Type_Boolean:
+ return value.b ? QStringLiteral("true") : QStringLiteral("false");
+ case Type_Number:
+ return QString::number(value.d);
+ case Type_Invalid:
+ return QString();
+ default:
+ break;
+ }
+ return QString();
+}
+
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 235202a832..8481e17857 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -44,6 +44,7 @@
#include <QtCore/qstring.h>
#include <QVector>
#include <QStringList>
+#include <QHash>
#include <private/qv4value_def_p.h>
#include <private/qv4executableallocator_p.h>
@@ -67,6 +68,22 @@ struct Function;
struct Lookup;
struct RegExp;
+struct Location
+{
+ int line;
+ int column;
+};
+
+// map from name index to location of first use
+struct TypeReferenceMap : QHash<int, Location>
+{
+ void add(int nameIndex, const Location &loc) {
+ if (contains(nameIndex))
+ return;
+ insert(nameIndex, loc);
+ }
+};
+
struct RegExp
{
enum Flags {
@@ -178,9 +195,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()
@@ -207,6 +224,7 @@ struct Function
quint32 lineNumberMappingOffset; // Array of uint pairs (offset and line number)
quint32 nInnerFunctions;
quint32 innerFunctionsOffset;
+ Location location;
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
@@ -223,79 +241,197 @@ struct Function
// Qml data structures
-struct Value
+struct Binding
{
- quint32 type; // Invalid, Boolean, Number, String, Function, Object, ListOfObjects
+ quint32 propertyNameIndex;
+
+ enum ValueType {
+ Type_Invalid,
+ Type_Boolean,
+ Type_Number,
+ Type_String,
+ Type_Script,
+ Type_Object,
+ Type_AttachedProperty,
+ Type_GroupProperty
+ };
+
+ enum Flags {
+ IsSignalHandlerExpression = 0x1
+ };
+
+ quint32 flags : 16;
+ quint32 type : 16;
union {
bool b;
- int i;
double d;
- quint32 offsetToString;
- quint32 offsetToFunction;
- quint32 offsetToObject;
- };
-};
+ quint32 compiledScriptIndex; // used when Type_Script
+ quint32 objectIndex;
+ } value;
+ quint32 stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
+
+ Location location;
+
+ QString valueAsString(const Unit *unit) const;
+ double valueAsNumber() const
+ {
+ if (type == Type_Number)
+ return value.d;
+ return 0.0;
+
+ }
+ bool valueAsBoolean() const
+ {
+ if (type == Type_Boolean)
+ return value.b;
+ return false;
+ }
-struct Binding
-{
- quint32 offsetToPropertyName;
- Value value;
};
struct Parameter
{
- quint32 offsetToName;
+ quint32 nameIndex;
quint32 type;
- quint32 offsetToCustomTypeName;
+ quint32 customTypeNameIndex;
quint32 reserved;
+ Location location;
};
struct Signal
{
- quint32 offsetToName;
+ quint32 nameIndex;
quint32 nParameters;
- Parameter parameters[1];
+ Location location;
+ // 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;
+ union {
+ quint32 customTypeNameIndex; // If type >= Custom
+ quint32 aliasIdValueIndex; // If type == Alias
+ };
+ quint32 aliasPropertyValueIndex;
+ quint32 flags; // readonly
+ Location location;
};
struct Object
{
- quint32 offsetToInheritedTypeName;
- quint32 offsetToId;
- quint32 offsetToDefaultProperty;
+ // Depending on the use, this may be the type name to instantiate before instantiating this
+ // object. For grouped properties the type name will be empty and for attached properties
+ // it will be the name of the attached type.
+ 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;
+ Location location;
+ Location locationOfIdProperty;
// 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 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,14 +440,16 @@ struct QmlUnit
// CompilationUnit * (for functions that need to clean up)
// CompiledData::Function *compiledFunction
-struct CompilationUnit
+struct Q_QML_EXPORT CompilationUnit
{
CompilationUnit()
: refCount(0)
, engine(0)
, data(0)
+ , ownsData(false)
, runtimeStrings(0)
, runtimeLookups(0)
+ , runtimeRegularExpressions(0)
, runtimeClasses(0)
{}
virtual ~CompilationUnit();
@@ -322,6 +460,7 @@ struct CompilationUnit
int refCount;
ExecutionEngine *engine;
Unit *data;
+ bool ownsData;
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
@@ -333,6 +472,7 @@ struct CompilationUnit
// QVector<QV4::Function *> runtimeFunctionsSortedByAddress;
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
+ void unlink();
virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; }
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 322a39932a..8cd4c8e2d8 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();
@@ -286,6 +293,9 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
function->nInnerFunctions = irFunction->nestedFunctions.size();
function->innerFunctionsOffset = function->lineNumberMappingOffset + function->nLineNumberMappingEntries * 2 * sizeof(quint32);
+ function->location.line = irFunction->line;
+ function->location.column = irFunction->column;
+
// write formals
quint32 *formals = (quint32 *)(f + function->formalsOffset);
for (int i = 0; i < irFunction->formals.size(); ++i)
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 b753b875de..a6a245e5ca 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -502,7 +502,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
lineNumberMapping[i * 2] = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
lineNumberMapping[i * 2 + 1] = codeLineNumberMappings.at(i).lineNumber;
}
- _isel->registerLineNumberMapping(_function, lineNumberMapping);
+ _isel->jsUnitGenerator()->registerLineNumberMapping(_function, lineNumberMapping);
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
@@ -584,8 +584,8 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
-InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
- : EvalInstructionSelection(execAllocator, module)
+InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
+ : EvalInstructionSelection(execAllocator, module, jsGenerator)
, _block(0)
, _function(0)
, _as(0)
@@ -702,7 +702,6 @@ void *InstructionSelection::addConstantTable(QVector<Value> *values)
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
{
- compilationUnit->data = generateUnit();
return compilationUnit;
}
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index adb426d674..c74dcd362d 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -1315,7 +1315,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module);
+ InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -1529,8 +1529,8 @@ class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
- { return new InstructionSelection(execAllocator, module); }
+ virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ { return new InstructionSelection(execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return true; }
};
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 99ca3c5d4e..b3e837d158 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -205,8 +205,8 @@ private:
}
};
-InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
- : EvalInstructionSelection(execAllocator, module)
+InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ : EvalInstructionSelection(execAllocator, module, jsGenerator)
, _function(0)
, _block(0)
, _codeStart(0)
@@ -281,7 +281,7 @@ void InstructionSelection::run(int functionIndex)
}
}
- registerLineNumberMapping(_function, lineNumberMappings);
+ jsGenerator->registerLineNumberMapping(_function, lineNumberMappings);
// TODO: patch stack size (the push instruction)
patchJumpAddresses();
@@ -305,7 +305,6 @@ void InstructionSelection::run(int functionIndex)
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
{
- compilationUnit->data = generateUnit();
compilationUnit->codeRefs.resize(irModule->functions.size());
int i = 0;
foreach (V4IR::Function *irFunction, irModule->functions)
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index df6095db5b..ee0b7276cb 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -71,7 +71,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module);
+ InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -188,8 +188,8 @@ class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
- { return new InstructionSelection(execAllocator, module); }
+ virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ { return new InstructionSelection(execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return false; }
};
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 7989232926..2f66628fea 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -58,11 +58,16 @@ QTextStream qout(stderr, QIODevice::WriteOnly);
using namespace QQmlJS;
using namespace QQmlJS::V4IR;
-EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module)
- : QV4::Compiler::JSUnitGenerator(module)
- , useFastLookups(true)
+EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ : useFastLookups(true)
, executableAllocator(execAllocator)
+ , irModule(module)
{
+ if (!jsGenerator) {
+ jsGenerator = new QV4::Compiler::JSUnitGenerator(module);
+ ownJSGenerator.reset(jsGenerator);
+ }
+ this->jsGenerator = jsGenerator;
assert(execAllocator);
assert(module);
}
@@ -73,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)
@@ -81,7 +86,12 @@ QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile()
for (int i = 0; i < irModule->functions.size(); ++i)
run(i);
- 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 e1cccedd2c..4b82d154d9 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -59,30 +59,40 @@ struct Function;
namespace QQmlJS {
-class Q_QML_EXPORT EvalInstructionSelection : public QV4::Compiler::JSUnitGenerator
+class Q_QML_EXPORT EvalInstructionSelection
{
public:
- EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module);
+ 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; }
+ int registerString(const QString &str) { return jsGenerator->registerString(str); }
+ uint registerGetterLookup(const QString &name) { return jsGenerator->registerGetterLookup(name); }
+ uint registerSetterLookup(const QString &name) { return jsGenerator->registerSetterLookup(name); }
+ uint registerGlobalGetterLookup(const QString &name) { return jsGenerator->registerGlobalGetterLookup(name); }
+ int registerRegExp(QQmlJS::V4IR::RegExp *regexp) { return jsGenerator->registerRegExp(regexp); }
+ int registerJSClass(QQmlJS::V4IR::ExprList *args) { return jsGenerator->registerJSClass(args); }
+ QV4::Compiler::JSUnitGenerator *jsUnitGenerator() const { return jsGenerator; }
+
protected:
virtual void run(int functionIndex) = 0;
virtual QV4::CompiledData::CompilationUnit *backendCompileStep() = 0;
-protected:
bool useFastLookups;
QV4::ExecutableAllocator *executableAllocator;
+ QV4::Compiler::JSUnitGenerator *jsGenerator;
+ QScopedPointer<QV4::Compiler::JSUnitGenerator> ownJSGenerator;
+ V4IR::Module *irModule;
};
class Q_QML_EXPORT EvalISelFactory
{
public:
virtual ~EvalISelFactory() = 0;
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module) = 0;
+ virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
virtual bool jitCompileRegexps() const = 0;
};
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 224b55a1a4..69771837fe 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -622,9 +622,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/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index d849b50ea2..67168ef951 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -714,6 +714,10 @@ struct Function {
uint hasWith: 1;
uint unused : 26;
+ // Location of declaration in source code (-1 if not specified)
+ int line;
+ int column;
+
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
Function(Module *module, Function *outer, const QString &name)
@@ -730,6 +734,8 @@ struct Function {
, hasTry(false)
, hasWith(false)
, unused(0)
+ , line(-1)
+ , column(-1)
{ this->name = newString(name); }
~Function();
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 56701457e4..6a97b9cfab 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -271,10 +271,12 @@ void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, F
activation = qml;
- compilationUnit = function->function->compilationUnit;
- compiledFunction = function->function->compiledFunction;
- lookups = compilationUnit->runtimeLookups;
- runtimeStrings = compilationUnit->runtimeStrings;
+ if (function->function) {
+ compilationUnit = function->function->compilationUnit;
+ compiledFunction = function->function->compiledFunction;
+ lookups = compilationUnit->runtimeLookups;
+ runtimeStrings = compilationUnit->runtimeStrings;
+ }
locals = (Value *)(this + 1);
if (function->varCount)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 1a084905ae..daa58d5e81 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -296,6 +296,12 @@ ExecutionEngine::~ExecutionEngine()
m_multiplyWrappedQObjects = 0;
delete identifierTable;
delete memoryManager;
+
+ QSet<QV4::CompiledData::CompilationUnit*> remainingUnits;
+ qSwap(compilationUnits, remainingUnits);
+ foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits)
+ unit->unlink();
+
delete m_qmlExtensions;
emptyClass->destroy();
delete bumperPointerAllocator;
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index a754663556..e539d62d54 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -52,6 +52,14 @@ void *ExecutableAllocator::Allocation::start() const
return reinterpret_cast<void*>(addr);
}
+void ExecutableAllocator::Allocation::deallocate(ExecutableAllocator *allocator)
+{
+ if (isValid())
+ allocator->free(this);
+ else
+ delete this;
+}
+
ExecutableAllocator::Allocation *ExecutableAllocator::Allocation::split(size_t dividingSize)
{
Allocation *remainder = new Allocation;
@@ -117,7 +125,8 @@ ExecutableAllocator::ChunkOfPages::~ChunkOfPages()
Allocation *alloc = firstAllocation;
while (alloc) {
Allocation *next = alloc->next;
- delete alloc;
+ if (alloc->isValid())
+ delete alloc;
alloc = next;
}
pages->deallocate();
@@ -135,13 +144,25 @@ bool ExecutableAllocator::ChunkOfPages::contains(Allocation *alloc) const
return false;
}
+ExecutableAllocator::ExecutableAllocator()
+ : mutex(QMutex::NonRecursive)
+{
+}
+
ExecutableAllocator::~ExecutableAllocator()
{
+ foreach (ChunkOfPages *chunk, chunks) {
+ for (Allocation *allocation = chunk->firstAllocation; allocation; allocation = allocation->next)
+ if (!allocation->free)
+ allocation->invalidate();
+ }
+
qDeleteAll(chunks);
}
ExecutableAllocator::Allocation *ExecutableAllocator::allocate(size_t size)
{
+ QMutexLocker locker(&mutex);
Allocation *allocation = 0;
// Code is best aligned to 16-byte boundaries.
@@ -182,6 +203,8 @@ ExecutableAllocator::Allocation *ExecutableAllocator::allocate(size_t size)
void ExecutableAllocator::free(Allocation *allocation)
{
+ QMutexLocker locker(&mutex);
+
assert(allocation);
allocation->free = true;
@@ -210,6 +233,8 @@ void ExecutableAllocator::free(Allocation *allocation)
ExecutableAllocator::ChunkOfPages *ExecutableAllocator::chunkForAllocation(Allocation *allocation) const
{
+ QMutexLocker locker(&mutex);
+
QMap<quintptr, ChunkOfPages*>::ConstIterator it = chunks.lowerBound(allocation->addr);
if (it != chunks.begin())
--it;
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index 2a304baf9c..b4fb2fb0e5 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -48,6 +48,7 @@
#include <QHash>
#include <QVector>
#include <QByteArray>
+#include <QMutex>
namespace WTF {
class PageAllocation;
@@ -63,6 +64,7 @@ public:
struct ChunkOfPages;
struct Allocation;
+ ExecutableAllocator();
~ExecutableAllocator();
Allocation *allocate(size_t size);
@@ -79,8 +81,13 @@ public:
{}
void *start() const;
+ void invalidate() { addr = 0; }
+ bool isValid() const { return addr != 0; }
+ void deallocate(ExecutableAllocator *allocator);
private:
+ ~Allocation() {}
+
friend class ExecutableAllocator;
Allocation *split(size_t dividingSize);
@@ -125,6 +132,7 @@ public:
private:
QMultiMap<size_t, Allocation*> freeAllocations;
QMap<quintptr, ChunkOfPages*> chunks;
+ mutable QMutex mutex;
};
}
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 2e03df4871..b93eded3f3 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>
#include <private/qv4engine_p.h>
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index a13aa2c29d..0cf235475e 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -249,7 +249,8 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module));
+ QV4::Compiler::JSUnitGenerator jsGenerator(&module);
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 1834e28be6..7dd3bbeb66 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -60,39 +60,59 @@
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();
- }
+QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Object *qml)
+ : FunctionObject(scope, scope->engine->id_eval)
+ , qml(qml)
+{
+ vtbl = &static_vtbl;
+ function = 0;
+ usesArgumentsObject = false;
+ needsActivation = false;
+ defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(1));
+
+ qmlContext = scope->engine->current->newQmlContext(this, qml);
+ scope->engine->popContext();
+}
- static ReturnedValue call(Managed *that, CallData *);
- static void markObjects(Managed *m)
- {
- QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
- if (wrapper->qml)
- wrapper->qml->mark();
- FunctionObject::markObjects(m);
- wrapper->qmlContext->mark();
- }
+ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
+{
+ ExecutionEngine *engine = that->engine();
+ Scope scope(engine);
+ QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
+ Q_ASSERT(This->function);
-private:
- Object *qml;
- CallContext *qmlContext;
-};
+ CallContext *ctx = This->qmlContext;
+ std::fill(ctx->locals, ctx->locals + ctx->function->varCount, Value::undefinedValue());
+ engine->pushContext(ctx);
+ ScopedValue result(scope, This->function->code(ctx, This->function->codeData));
+ engine->popContext();
+
+ return result.asReturnedValue();
+}
+
+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);
@@ -122,23 +142,6 @@ struct CompilationUnitHolder : public QV4::Object
DEFINE_MANAGED_VTABLE(CompilationUnitHolder);
-ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
-{
- ExecutionEngine *engine = that->engine();
- Scope scope(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);
- ScopedValue result(scope, This->function->code(ctx, This->function->codeData));
- engine->popContext();
-
- return result.asReturnedValue();
-
-}
-
-
Script::~Script()
{
}
@@ -192,7 +195,8 @@ void Script::parse()
RuntimeCodegen cg(scope, strictMode);
cg.generateFromProgram(sourceFile, sourceCode, program, &module,
parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
- QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module));
+ QV4::Compiler::JSUnitGenerator jsGenerator(&module);
+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
if (inheritContext)
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 46f28ccb1e..752cb2ac53 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,23 @@ namespace QV4 {
struct ExecutionContext;
+struct QmlBindingWrapper : FunctionObject {
+ Q_MANAGED
+
+ QmlBindingWrapper(ExecutionContext *scope, Function *f, Object *qml);
+ // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable!
+ QmlBindingWrapper(ExecutionContext *scope, Object *qml);
+
+ static ReturnedValue call(Managed *that, CallData *);
+ static void markObjects(Managed *m);
+
+ CallContext *context() const { return qmlContext; }
+
+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 29c007ad07..3bba6f8e83 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -55,7 +55,8 @@ SOURCES += \
$$PWD/qqmlcontextwrapper.cpp \
$$PWD/qqmlvaluetypewrapper.cpp \
$$PWD/qqmltypewrapper.cpp \
- $$PWD/qqmlfileselector.cpp
+ $$PWD/qqmlfileselector.cpp \
+ $$PWD/qqmlobjectcreator.cpp
HEADERS += \
$$PWD/qqmlglobal_p.h \
@@ -133,7 +134,8 @@ HEADERS += \
$$PWD/qqmlvaluetypewrapper_p.h \
$$PWD/qqmltypewrapper_p.h \
$$PWD/qqmlfileselector_p.h \
- $$PWD/qqmlfileselector.h
+ $$PWD/qqmlfileselector.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..ebe81d647a 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -60,6 +60,8 @@
QT_BEGIN_NAMESPACE
+class QmlObjectCreator;
+
class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
{
public:
@@ -150,6 +152,7 @@ private:
friend class QQmlVME;
friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
friend class QV4Bindings;
+ friend class QmlObjectCreator;
typedef QSharedPointer<QQmlAbstractBinding> SharedPointer;
// To save memory, we also store the rarely used weakPointer() instance in here
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 3242ab9831..36cbc39d40 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -86,6 +86,19 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
m_expression = expression;
}
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::PersistentValue &function)
+ : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
+ m_v8function(function),
+ m_line(-1),
+ m_column(-1),
+ m_target(target),
+ m_index(index),
+ m_expressionFunctionValid(true),
+ m_invalidParameterName(false)
+{
+ init(ctxt, scope);
+}
+
void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
{
setNotifyOnValueChanged(false);
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index ffb3d06770..86e3dc20ea 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -75,6 +75,9 @@ public:
const QString &handlerName = QString(),
const QString &parameterString = QString());
+ QQmlBoundSignalExpression(QObject *target, int index,
+ QQmlContextData *ctxt, QObject *scope, const QV4::PersistentValue &function);
+
// "inherited" from QQmlJavaScriptExpression.
static QString expressionIdentifier(QQmlJavaScriptExpression *);
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index abe278f570..35de0ac358 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);
@@ -116,8 +116,17 @@ QQmlCompiledData::~QQmlCompiledData()
types.at(ii).typePropertyCache->release();
}
+ for (QHash<int, TypeReference>::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end();
+ resolvedType != end; ++resolvedType) {
+ if (resolvedType->component)
+ resolvedType->component->release();
+ if (resolvedType->typePropertyCache)
+ resolvedType->typePropertyCache->release();
+ }
+
for (int ii = 0; ii < propertyCaches.count(); ++ii)
- propertyCaches.at(ii)->release();
+ if (propertyCaches.at(ii))
+ propertyCaches.at(ii)->release();
for (int ii = 0; ii < scripts.count(); ++ii)
scripts.at(ii)->release();
@@ -127,6 +136,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..9e63ecb22c 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;
@@ -103,7 +110,12 @@ public:
QQmlPropertyCache *propertyCache() const;
QQmlPropertyCache *createPropertyCache(QQmlEngine *);
};
+ // --- old compiler:
QList<TypeReference> types;
+ // --- new compiler:
+ // map from name index
+ QHash<int, TypeReference> resolvedTypes;
+ // ---
struct V8Program {
V8Program(const QByteArray &p, QQmlCompiledData *c)
@@ -125,6 +137,16 @@ public:
QList<QQmlScriptData *> scripts;
QList<QUrl> urls;
+ // --- new compiler
+ QV4::CompiledData::CompilationUnit *compilationUnit;
+ QV4::CompiledData::QmlUnit *qmlUnit;
+ // index in first hash is component index, hash inside maps from object index in that scope to integer id
+ QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
+ QHash<int, int> objectIndexToIdForRoot;
+
+ bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
+ // ---
+
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 ce8f71f9ba..3c8a50ad4f 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -894,8 +894,20 @@ 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) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ if (cc->compilationUnit && !cc->compilationUnit->engine)
+ cc->compilationUnit->linkToEngine(v4);
+
+ state.creator = new QmlObjectCreator(context, cc);
+ rv = state.creator->create(start);
+ 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) {
@@ -935,14 +947,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) {
+ state->creator->finalize();
+ } else {
+ state->vme.complete();
+ }
state->completePending = false;
@@ -1015,9 +1035,11 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
if (!engine)
return a;
- if (QQmlEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin
- QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
+ QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
+ if (p->activeVME) { // XXX should only be allowed during begin
a->add(&p->activeVME->componentAttached);
+ } else if (p->activeObjectCreator) {
+ a->add(&p->activeObjectCreator->componentAttached);
} else {
QQmlData *d = QQmlData::get(obj);
Q_ASSERT(d);
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 9877f59fb6..fe376d0e4a 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -129,6 +129,7 @@ private:
Q_DISABLE_COPY(QQmlComponent)
friend class QQmlVME;
friend class QQmlTypeData;
+ friend class QmlObjectCreator;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 439f1fcdd9..08e4dcea7d 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
+ 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 f3a1867d18..afb993499d 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -547,16 +547,19 @@ 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),
outputWarningsToStdErr(true),
cleanup(0), erroredBindings(0), inProgressCreations(0),
workerScriptEngine(0), activeVME(0),
+ activeObjectCreator(0),
networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
{
+ useNewCompiler = qmlUseNewCompiler();
}
QQmlEnginePrivate::~QQmlEnginePrivate()
@@ -1028,6 +1031,8 @@ void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
{
if (activeVME) {
activeVME->finalizeCallbacks.append(qMakePair(QPointer<QObject>(obj), index));
+ } else if (activeObjectCreator) {
+ activeObjectCreator->finalizeCallbacks.append(qMakePair(QPointer<QObject>(obj), index));
} else {
void *args[] = { 0 };
QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index c57c70fa40..c67e45a833 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -99,6 +99,7 @@ class QQmlCleanup;
class QQmlDelayedError;
class QQuickWorkerScriptEngine;
class QQmlVME;
+class QmlObjectCreator;
class QDir;
class QQmlIncubator;
@@ -144,6 +145,7 @@ public:
QQmlContext *rootContext;
bool isDebugging;
+ bool useNewCompiler;
bool outputWarningsToStdErr;
@@ -165,7 +167,11 @@ public:
typedef QPair<QPointer<QObject>,int> FinalizeCallback;
void registerFinalizeCallback(QObject *obj, int index);
+ // --- old compiler:
QQmlVME *activeVME;
+ // --- new compiler:
+ QmlObjectCreator *activeObjectCreator;
+ // ---
QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
QNetworkAccessManager *getNetworkAccessManager() const;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
new file mode 100644
index 0000000000..b4201fd10a
--- /dev/null
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -0,0 +1,1575 @@
+/****************************************************************************
+**
+** 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>
+#include <private/qqmlboundsignal_p.h>
+#include <private/qqmltrace_p.h>
+#include <private/qqmlcomponentattached_p.h>
+#include <QQmlComponent>
+#include <private/qqmlcomponent_p.h>
+#include <private/qqmlcodegenerator_p.h>
+
+QT_USE_NAMESPACE
+
+namespace {
+struct ActiveOCRestorer
+{
+ ActiveOCRestorer(QmlObjectCreator *creator, QQmlEnginePrivate *ep)
+ : ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
+ ~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
+
+ QQmlEnginePrivate *ep;
+ QmlObjectCreator *oldCreator;
+};
+}
+
+QQmlCompilePass::QQmlCompilePass(const QUrl &url, const QV4::CompiledData::QmlUnit *unit)
+ : url(url)
+ , qmlUnit(unit)
+{
+}
+
+void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description)
+{
+ QQmlError error;
+ error.setUrl(url);
+ error.setLine(location.line);
+ error.setColumn(location.column);
+ error.setDescription(description);
+ errors << error;
+}
+
+#define COMPILE_EXCEPTION(token, desc) \
+ { \
+ recordError((token)->location, desc); \
+ return false; \
+ }
+
+static QAtomicInt classIndexCounter(0);
+
+QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit, const QUrl &url, const QQmlImports *imports,
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes)
+ : QQmlCompilePass(url, unit)
+ , enginePrivate(enginePrivate)
+ , imports(imports)
+ , resolvedTypes(resolvedTypes)
+{
+}
+
+bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **resultCache, QByteArray *vmeMetaObjectData)
+{
+ Q_ASSERT(!stringAt(obj->inheritedTypeNameIndex).isEmpty());
+
+ QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ Q_ASSERT(baseTypeCache);
+ if (obj->nProperties == 0 && obj->nSignals == 0 && obj->nFunctions == 0) {
+ *resultCache = baseTypeCache;
+ vmeMetaObjectData->clear();
+ return true;
+ }
+
+ QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate),
+ obj->nProperties,
+ obj->nFunctions + obj->nProperties + obj->nSignals,
+ obj->nSignals + obj->nProperties);
+ *resultCache = 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);
+ const QString customTypeName = stringAt(param->customTypeNameIndex);
+ QQmlType *qmltype = 0;
+ if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0))
+ COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(customTypeName));
+
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->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))
+ COMPILE_EXCEPTION(s, tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
+ 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 = qmlUnit->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))
+ COMPILE_EXCEPTION(s, tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+ // 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 = enginePrivate->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 = qmlUnit->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;
+}
+
+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(QQmlContextData *parentContext, QQmlCompiledData *compiledData)
+ : QQmlCompilePass(compiledData->url, compiledData->qmlUnit)
+ , componentAttached(0)
+ , engine(parentContext->engine)
+ , jsUnit(compiledData->compilationUnit)
+ , parentContext(parentContext)
+ , context(0)
+ , resolvedTypes(compiledData->resolvedTypes)
+ , propertyCaches(compiledData->propertyCaches)
+ , vmeMetaObjectData(compiledData->datas)
+ , compiledData(compiledData)
+ , _qobject(0)
+ , _compiledObject(0)
+ , _ddata(0)
+ , _propertyCache(0)
+ , _vmeMetaObject(0)
+ , _qmlContext(0)
+{
+}
+
+QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
+{
+ int objectToCreate;
+
+ if (subComponentIndex == -1) {
+ objectIndexToId = compiledData->objectIndexToIdForRoot;
+ objectToCreate = qmlUnit->indexOfRootObject;
+ } else {
+ objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex];
+ const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
+ objectToCreate = compObj->bindingTable()->value.objectIndex;
+ }
+
+ context = new QQmlContextData;
+ context->isInternal = true;
+ context->url = compiledData->url;
+ context->urlString = compiledData->name;
+ context->imports = compiledData->importCache;
+ context->imports->addref();
+ context->setParent(parentContext);
+
+ QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count());
+ for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
+ it != end; ++it) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(it.key());
+
+ QQmlContextData::ObjectIdMapping m;
+ m.id = it.value();
+ m.name = stringAt(obj->idIndex);
+ mapping[m.id] = m;
+ }
+ context->setIdPropertyData(mapping);
+
+ QObject *instance = createInstance(objectToCreate, parent);
+ if (instance) {
+ QQmlData *ddata = QQmlData::get(instance);
+ Q_ASSERT(ddata);
+ ddata->compiledData = compiledData;
+ ddata->compiledData->addref();
+
+ QQmlEnginePrivate::get(engine)->registerInternalCompositeType(compiledData);
+ }
+ return instance;
+}
+
+void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
+{
+ QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ int propertyWriteStatus = -1;
+ void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
+
+ // ### enums
+
+ switch (property->propType) {
+ case QMetaType::QVariant: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double n = binding->valueAsNumber();
+ if (double(int(n)) == n) {
+ if (property->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Value::fromInt32(int(n)));
+ } else {
+ int i = int(n);
+ QVariant value(i);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ } else {
+ if (property->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Value::fromDouble(n));
+ } else {
+ QVariant value(n);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ }
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ if (property->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Value::fromBoolean(binding->valueAsBoolean()));
+ } else {
+ QVariant value(binding->valueAsBoolean());
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ } else {
+ QString stringValue = binding->valueAsString(&qmlUnit->header);
+ if (property->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Value::fromString(QV8Engine::getV4(engine), stringValue));
+ } else {
+ QVariant value = QQmlStringConverters::variantFromString(stringValue);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ }
+ }
+ break;
+ case QVariant::String: {
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ QString value = binding->valueAsString(&qmlUnit->header);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: string expected"));
+ }
+ }
+ break;
+ case QVariant::StringList: {
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ QStringList value(binding->valueAsString(&qmlUnit->header));
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: string or string list expected"));
+ }
+ }
+ break;
+ case QVariant::ByteArray: {
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: byte array expected"));
+ }
+ }
+ break;
+ case QVariant::Url: {
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ QString string = binding->valueAsString(&qmlUnit->header);
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+ QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
+ // Apply URL interceptor
+ if (engine->urlInterceptor())
+ value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: url expected"));
+ }
+ }
+ break;
+ case QVariant::UInt: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(uint(d)) == d) {
+ uint value = uint(d);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ break;
+ }
+ }
+ recordError(binding->location, tr("Invalid property assignment: unsigned int expected"));
+ }
+ break;
+ case QVariant::Int: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double d = binding->valueAsNumber();
+ if (double(int(d)) == d) {
+ int value = int(d);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ break;
+ }
+ }
+ recordError(binding->location, tr("Invalid property assignment: int expected"));
+ }
+ break;
+ case QMetaType::Float: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ float value = float(binding->valueAsNumber());
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: number expected"));
+ }
+ }
+ break;
+ case QVariant::Double: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double value = binding->valueAsNumber();
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: number expected"));
+ }
+ }
+ break;
+ case QVariant::Color: {
+ bool ok = false;
+ uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
+
+ if (ok) {
+ struct { void *data[4]; } buffer;
+ if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
+ argv[0] = reinterpret_cast<void *>(&buffer);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: color expected"));
+ }
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date: {
+ bool ok = false;
+ QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: date expected"));
+ }
+ }
+ break;
+ case QVariant::Time: {
+ bool ok = false;
+ QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: time expected"));
+ }
+ }
+ break;
+ case QVariant::DateTime: {
+ bool ok = false;
+ QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: datetime expected"));
+ }
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point: {
+ bool ok = false;
+ QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::PointF: {
+ bool ok = false;
+ QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::Size: {
+ bool ok = false;
+ QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: size expected"));
+ }
+ }
+ break;
+ case QVariant::SizeF: {
+ bool ok = false;
+ QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: size expected"));
+ }
+ }
+ break;
+ case QVariant::Rect: {
+ bool ok = false;
+ QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::RectF: {
+ bool ok = false;
+ QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+ if (ok) {
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: point expected"));
+ }
+ }
+ break;
+ case QVariant::Bool: {
+ if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ bool value = binding->valueAsBoolean();
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: boolean expected"));
+ }
+ }
+ break;
+ case QVariant::Vector3D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ } vec;
+ if (QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
+ argv[0] = reinterpret_cast<void *>(&vec);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: 3D vector expected"));
+ }
+ }
+ break;
+ case QVariant::Vector4D: {
+ struct {
+ float xp;
+ float yp;
+ float zy;
+ float wp;
+ } vec;
+ if (QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
+ argv[0] = reinterpret_cast<void *>(&vec);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: 4D vector expected"));
+ }
+ }
+ break;
+ case QVariant::RegExp:
+ recordError(binding->location, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ break;
+ default: {
+ // generate single literal value assignment to a list property if required
+ if (property->propType == qMetaTypeId<QList<qreal> >()) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ QList<qreal> value;
+ value.append(binding->valueAsNumber());
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: real or array of reals expected"));
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<int> >()) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double n = binding->valueAsNumber();
+ if (double(int(n)) == n) {
+ QList<int> value;
+ value.append(int(n));
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ break;
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: int or array of ints expected"));
+ }
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<bool> >()) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ QList<bool> value;
+ value.append(binding->valueAsBoolean());
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: bool or array of bools expected"));
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ QString urlString = binding->valueAsString(&qmlUnit->header);
+ QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
+ QList<QUrl> value;
+ value.append(u);
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: url or array of urls expected"));
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QList<QString> >()) {
+ if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ QList<QString> value;
+ value.append(binding->valueAsString(&qmlUnit->header));
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: string or array of strings expected"));
+ }
+ break;
+ } else if (property->propType == qMetaTypeId<QJSValue>()) {
+ QJSValue value;
+ if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ value = QJSValue(binding->valueAsBoolean());
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ double n = binding->valueAsNumber();
+ if (double(int(n)) == n) {
+ value = QJSValue(int(n));
+ } else
+ value = QJSValue(n);
+ } else {
+ value = QJSValue(binding->valueAsString(&qmlUnit->header));
+ }
+ argv[0] = reinterpret_cast<void *>(&value);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ break;
+ }
+
+ // otherwise, try a custom type assignment
+ QString stringValue = binding->valueAsString(&qmlUnit->header);
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
+ if (converter) {
+ QVariant value = (*converter)(stringValue);
+
+ QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
+ if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
+ recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
+ break;
+ }
+
+ argv[0] = value.data();
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
+ }
+ }
+ break;
+ }
+}
+
+void QmlObjectCreator::setupBindings()
+{
+ QQmlListProperty<void> savedList;
+ qSwap(_currentList, savedList);
+
+ QQmlPropertyData *property = 0;
+
+ const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
+ for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
+
+ if (!property || (i > 0 && (binding - 1)->propertyNameIndex != binding->propertyNameIndex)) {
+ QString name = stringAt(binding->propertyNameIndex);
+ if (!name.isEmpty())
+ property = _propertyCache->property(name, _qobject, context);
+ else
+ property = 0;
+
+ if (property && property->isQList()) {
+ void *argv[1] = { (void*)&_currentList };
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
+ } else if (_currentList.object)
+ _currentList = QQmlListProperty<void>();
+
+ }
+
+ if (!setPropertyValue(property, i, binding))
+ return;
+ }
+
+ qSwap(_currentList, savedList);
+}
+
+bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
+{
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(binding->value.objectIndex);
+ Q_ASSERT(stringAt(obj->inheritedTypeNameIndex).isEmpty());
+ QQmlType *attachedType = resolvedTypes.value(binding->propertyNameIndex).type;
+ const int id = attachedType->attachedPropertiesId();
+ QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
+ QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(qmlObject);
+ if (!populateInstance(binding->value.objectIndex, qmlObject, cache, _qobject))
+ return false;
+ return true;
+ }
+
+ QObject *createdSubObject = 0;
+ if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ createdSubObject = createInstance(binding->value.objectIndex, _qobject);
+ if (!createdSubObject)
+ return false;
+ }
+
+ // Child item:
+ // ...
+ // Item {
+ // ...
+ // }
+ if (!property)
+ return true;
+
+ if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(binding->value.objectIndex);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
+ QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property->propType);
+ if (!valueType) {
+ recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
+ return false;
+ }
+
+ valueType->read(_qobject, property->coreIndex);
+
+ QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(valueType);
+ if (!populateInstance(binding->value.objectIndex, valueType, cache, _qobject))
+ return false;
+
+ valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor);
+ return true;
+ }
+ }
+
+ if (_ddata->hasBindingBit(property->coreIndex))
+ removeBindingOnProperty(_qobject, property->coreIndex);
+
+ if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QV4::Value function = QV4::Value::fromObject(QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction));
+
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
+ int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
+ QQmlBoundSignal *bs = new QQmlBoundSignal(_qobject, signalIndex, _qobject, engine);
+ QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_qobject, signalIndex,
+ context, _qobject, function);
+
+ bs->takeExpression(expr);
+ } else {
+ QQmlBinding *qmlBinding = new QQmlBinding(function, _qobject, context,
+ QString(), 0, 0); // ###
+ qmlBinding->setTarget(_qobject, *property, context);
+ qmlBinding->addToObject();
+
+ _createdBindings[bindingIndex] = qmlBinding;
+ qmlBinding->m_mePtr = &_createdBindings[bindingIndex];
+ }
+ return true;
+ }
+
+ if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ int propertyWriteStatus = -1;
+ void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
+
+ if (const char *iid = QQmlMetaType::interfaceIId(property->propType)) {
+ void *ptr = createdSubObject->qt_metacast(iid);
+ if (ptr) {
+ argv[0] = &ptr;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Cannot assign object to interface property"));
+ return false;
+ }
+ } else if (property->propType == QMetaType::QVariant) {
+ if (property->isVarProperty()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope scope(v4);
+ QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), createdSubObject));
+ _vmeMetaObject->setVMEProperty(property->coreIndex, wrappedObject);
+ } else {
+ QVariant value = QVariant::fromValue(createdSubObject);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ } else if (property->isQList()) {
+ Q_ASSERT(_currentList.object);
+
+ void *itemToAdd = createdSubObject;
+
+ const char *iid = 0;
+ int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType);
+ if (listItemType != -1)
+ iid = QQmlMetaType::interfaceIId(listItemType);
+ if (iid)
+ itemToAdd = createdSubObject->qt_metacast(iid);
+
+ if (_currentList.append)
+ _currentList.append(&_currentList, itemToAdd);
+ } else {
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+
+ // We want to raw metaObject here as the raw metaobject is the
+ // actual property type before we applied any extensions that might
+ // effect the properties on the type, but don't effect assignability
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
+
+ // Will be true if the assgned type inherits propertyMetaObject
+ bool isAssignable = false;
+ // Determine isAssignable value
+ if (propertyMetaObject) {
+ QQmlPropertyCache *c = enginePrivate->cache(createdSubObject);
+ while (c && !isAssignable) {
+ isAssignable |= c == propertyMetaObject;
+ c = c->parent();
+ }
+ }
+
+ if (isAssignable) {
+ argv[0] = &createdSubObject;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Cannot assign object to property"));
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (property->isQList()) {
+ recordError(binding->location, tr("Cannot assign primitives to lists"));
+ return false;
+ }
+
+ setPropertyValue(property, binding);
+ return true;
+}
+
+void QmlObjectCreator::setupFunctions()
+{
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(_qobject);
+
+ const quint32 *functionIdx = _compiledObject->functionOffsetTable();
+ for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
+ QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[*functionIdx];
+ const QString name = runtimeFunction->name->toQString();
+
+ QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
+ if (!property->isVMEFunction())
+ continue;
+
+ QV4::FunctionObject *function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction);
+ vme->setVmeMethod(property->coreIndex, QV4::Value::fromObject(function));
+ }
+}
+
+QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
+{
+ ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+
+ bool isComponent = false;
+ QObject *instance = 0;
+
+ if (compiledData->isComponent(index)) {
+ isComponent = true;
+ QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
+ QQmlComponentPrivate::get(component)->creationContext = context;
+ instance = component;
+ } else {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+
+ QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ QQmlType *type = typeRef.type;
+ if (type) {
+ instance = type->create();
+ } else {
+ Q_ASSERT(typeRef.component);
+ QmlObjectCreator subCreator(context, typeRef.component);
+ instance = subCreator.create();
+ }
+ // ### use no-event variant
+ if (parent)
+ instance->setParent(parent);
+ }
+
+ QQmlData *ddata = QQmlData::get(instance, /*create*/true);
+ if (index == qmlUnit->indexOfRootObject) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != context);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != context);
+ QQmlContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = context;
+ } else
+ context->addObject(instance);
+ ddata->ownContext = true;
+ } else if (!ddata->context)
+ context->addObject(instance);
+
+ ddata->outerContext = context;
+
+ QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
+ if (idEntry != objectIndexToId.constEnd())
+ context->setIdProperty(idEntry.value(), instance);
+
+ if (!isComponent) {
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
+ Q_ASSERT(!cache.isNull());
+
+ if (!populateInstance(index, instance, cache, _qobject))
+ return 0;
+ }
+
+ return instance;
+}
+
+void QmlObjectCreator::finalize()
+{
+ {
+ QQmlTrace trace("VME Binding Enable");
+ trace.event("begin binding eval");
+
+ Q_ASSERT(allCreatedBindings.isEmpty() || allCreatedBindings.isDetached());
+
+ for (QLinkedList<QVector<QQmlAbstractBinding*> >::Iterator it = allCreatedBindings.begin(), end = allCreatedBindings.end();
+ it != end; ++it) {
+ const QVector<QQmlAbstractBinding *> &bindings = *it;
+ for (int i = 0; i < bindings.count(); ++i) {
+ QQmlAbstractBinding *b = bindings.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);
+ }
+ }
+ }
+
+ {
+ QQmlTrace trace("VME Component.onCompleted Callbacks");
+ while (componentAttached) {
+ QQmlComponentAttached *a = componentAttached;
+ a->rem();
+ QQmlData *d = QQmlData::get(a->parent());
+ Q_ASSERT(d);
+ Q_ASSERT(d->context);
+ a->add(&d->context->componentAttached);
+ // ### designer if (componentCompleteEnabled())
+ emit a->completed();
+
+#if 0 // ###
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ return 0;
+#endif
+ }
+ }
+}
+
+bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *scopeObjectForJavaScript)
+{
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+
+ if (!scopeObjectForJavaScript)
+ scopeObjectForJavaScript = instance;
+
+ QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
+
+ qSwap(_propertyCache, cache);
+ qSwap(_qobject, instance);
+ qSwap(_compiledObject, obj);
+ qSwap(_ddata, declarativeData);
+
+ QQmlVMEMetaObject *vmeMetaObject = 0;
+ const QByteArray data = vmeMetaObjectData.value(index);
+ if (!data.isEmpty()) {
+ // install on _object
+ vmeMetaObject = new QQmlVMEMetaObject(_qobject, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
+ if (_ddata->propertyCache)
+ _ddata->propertyCache->release();
+ _ddata->propertyCache = _propertyCache;
+ _ddata->propertyCache->addref();
+ } else {
+ vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
+ }
+
+ _ddata->lineNumber = _compiledObject->location.line;
+ _ddata->columnNumber = _compiledObject->location.column;
+
+ qSwap(_vmeMetaObject, vmeMetaObject);
+
+ QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
+ qSwap(_createdBindings, createdBindings);
+
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope valueScope(v4);
+ QV4::ScopedValue scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, scopeObjectForJavaScript));
+ QV4::QmlBindingWrapper *qmlBindingWrapper = new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject->asObject());
+ QV4::ScopedValue qmlScopeFunction(valueScope, QV4::Value::fromObject(qmlBindingWrapper));
+ QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
+
+ qSwap(_qmlContext, qmlContext);
+
+ setupBindings();
+ setupFunctions();
+
+ qSwap(_qmlContext, qmlContext);
+
+ qSwap(_createdBindings, createdBindings);
+ qSwap(_vmeMetaObject, vmeMetaObject);
+ qSwap(_propertyCache, cache);
+ qSwap(_ddata, declarativeData);
+ qSwap(_compiledObject, obj);
+ qSwap(_qobject, instance);
+
+ allCreatedBindings.append(_createdBindings);
+
+ return errors.isEmpty();
+}
+
+
+QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
+ const QList<QQmlPropertyCache *> &propertyCaches, QList<QByteArray> *vmeMetaObjectData,
+ QHash<int, int> *objectIndexToIdForRoot,
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent)
+ : QQmlCompilePass(url, qmlUnit)
+ , _componentIndex(-1)
+ , _objectIndexToIdInScope(0)
+ , resolvedTypes(resolvedTypes)
+ , propertyCaches(propertyCaches)
+ , vmeMetaObjectData(vmeMetaObjectData)
+ , objectIndexToIdForRoot(objectIndexToIdForRoot)
+ , objectIndexToIdPerComponent(objectIndexToIdPerComponent)
+{
+}
+
+bool QQmlComponentAndAliasResolver::resolve()
+{
+ Q_ASSERT(componentRoots.isEmpty());
+
+ // Find objects that are Components. This is missing an extra pass
+ // that finds implicitly defined components, i.e.
+ // someProperty: Item { ... }
+ // when someProperty _is_ a QQmlComponent. In that case the Item {}
+ // should be implicitly surrounded by Component {}
+
+ for (int i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ continue;
+
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(i);
+ if (!cache || cache->metaObject() != &QQmlComponent::staticMetaObject)
+ continue;
+
+ componentRoots.append(i);
+ // Sanity checks: There can be only an (optional) id property and
+ // a default property, that defines the component tree.
+ }
+
+ std::sort(componentRoots.begin(), componentRoots.end());
+
+ // For each component's tree, remember to which component the children
+ // belong to
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ const QV4::CompiledData::Object *component = qmlUnit->objectAt(componentRoots.at(i));
+
+ if (component->nFunctions > 0)
+ COMPILE_EXCEPTION(component, tr("Component objects cannot declare new functions."));
+ if (component->nProperties > 0)
+ COMPILE_EXCEPTION(component, tr("Component objects cannot declare new properties."));
+ if (component->nSignals > 0)
+ COMPILE_EXCEPTION(component, tr("Component objects cannot declare new signals."));
+
+ if (component->nBindings == 0)
+ COMPILE_EXCEPTION(component, tr("Cannot create empty component specification"));
+
+ const QV4::CompiledData::Binding *rootBinding = component->bindingTable();
+ if (component->nBindings > 1 || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
+ COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
+
+ _componentIndex = i;
+ _idToObjectIndex.clear();
+
+ _objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)];
+
+ _objectsWithAliases.clear();
+
+ if (!collectIdsAndAliases(rootBinding->value.objectIndex))
+ return false;
+
+ if (!resolveAliases())
+ return false;
+ }
+
+ // Collect ids and aliases for root
+ _componentIndex = -1;
+ _idToObjectIndex.clear();
+ _objectIndexToIdInScope = objectIndexToIdForRoot;
+ _objectsWithAliases.clear();
+
+ collectIdsAndAliases(qmlUnit->indexOfRootObject);
+
+ resolveAliases();
+
+ return errors.isEmpty();
+}
+
+bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
+{
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
+
+ // Only include creatable types. Everything else is synthetic, such as group property
+ // objects.
+ if (_componentIndex != -1 && !stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ objectIndexToComponentIndex.insert(objectIndex, _componentIndex);
+
+ QString id = stringAt(obj->idIndex);
+ if (!id.isEmpty()) {
+ if (_idToObjectIndex.contains(obj->idIndex)) {
+ recordError(obj->locationOfIdProperty, tr("id is not unique"));
+ return false;
+ }
+ _idToObjectIndex.insert(obj->idIndex, objectIndex);
+ _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
+ }
+
+ const QV4::CompiledData::Property *property = obj->propertyTable();
+ for (int i = 0; i < obj->nProperties; ++i, ++property)
+ if (property->type == QV4::CompiledData::Property::Alias) {
+ _objectsWithAliases.append(objectIndex);
+ break;
+ }
+
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (int i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Object
+ && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
+ && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ continue;
+
+ // Stop at Component boundary
+ if (std::binary_search(componentRoots.constBegin(), componentRoots.constEnd(), binding->value.objectIndex))
+ continue;
+
+ if (!collectIdsAndAliases(binding->value.objectIndex))
+ return false;
+ }
+
+ return true;
+}
+
+bool QQmlComponentAndAliasResolver::resolveAliases()
+{
+ foreach (int objectIndex, _objectsWithAliases) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
+
+ QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex);
+ Q_ASSERT(propertyCache);
+
+ int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
+ int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
+ int effectiveAliasIndex = 0;
+
+ const QV4::CompiledData::Property *p = obj->propertyTable();
+ for (quint32 propertyIndex = 0; propertyIndex < obj->nProperties; ++propertyIndex, ++p) {
+ if (p->type != QV4::CompiledData::Property::Alias)
+ continue;
+
+ const int idIndex = p->aliasIdValueIndex;
+ const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
+ if (targetObjectIndex == -1)
+ COMPILE_EXCEPTION(p, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1);
+ Q_ASSERT(targetId != -1);
+
+ const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex);
+
+ QStringRef property;
+ QStringRef subProperty;
+
+ const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
+ if (propertySeparator != -1) {
+ property = aliasPropertyValue.leftRef(propertySeparator);
+ subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
+ } else
+ property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
+
+ int propIdx = -1;
+ int propType = 0;
+ int notifySignal = -1;
+ int flags = 0;
+ int type = 0;
+ bool writable = false;
+ bool resettable = false;
+
+ quint32 propertyFlags = QQmlPropertyData::IsAlias;
+
+ if (property.isEmpty()) {
+ const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(targetObjectIndex);
+ QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex);
+
+ if (typeRef.type)
+ type = typeRef.type->typeId();
+ else
+ type = typeRef.component->metaTypeId;
+
+ flags |= QML_ALIAS_FLAG_PTR;
+ propertyFlags |= QQmlPropertyData::IsQObjectDerived;
+ } else {
+ QQmlPropertyCache *targetCache = propertyCaches.value(targetObjectIndex);
+ Q_ASSERT(targetCache);
+ QtQml::PropertyResolver resolver(targetCache);
+
+ QQmlPropertyData *targetProperty = resolver.property(property.toString());
+ if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF)
+ COMPILE_EXCEPTION(p, tr("Invalid alias location"));
+
+ propIdx = targetProperty->coreIndex;
+ type = targetProperty->propType;
+
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+ notifySignal = targetProperty->notifyIndex;
+
+ if (!subProperty.isEmpty()) {
+ QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
+ if (!valueType)
+ COMPILE_EXCEPTION(p, tr("Invalid alias location"));
+
+ propType = type;
+
+ int valueTypeIndex =
+ valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1)
+ COMPILE_EXCEPTION(p, tr("Invalid alias location"));
+ Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+
+ propIdx |= (valueTypeIndex << 16);
+ if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
+ type = QVariant::Int;
+ else
+ type = valueType->metaObject()->property(valueTypeIndex).userType();
+
+ } else {
+ if (targetProperty->isEnum()) {
+ type = QVariant::Int;
+ } else {
+ // Copy type flags
+ propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
+
+ if (targetProperty->isVarProperty())
+ propertyFlags |= QQmlPropertyData::IsQVariant;
+
+ if (targetProperty->isQObject())
+ flags |= QML_ALIAS_FLAG_PTR;
+ }
+ }
+ }
+
+ QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal };
+
+ typedef QQmlVMEMetaData VMD;
+ QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex];
+ Q_ASSERT(!dynamicData.isEmpty());
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
+
+ Q_ASSERT(dynamicData.isDetached());
+
+ if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
+ propertyFlags |= QQmlPropertyData::IsWritable;
+ else
+ propertyFlags &= ~QQmlPropertyData::IsWritable;
+
+ if (resettable)
+ propertyFlags |= QQmlPropertyData::IsResettable;
+ else
+ propertyFlags &= ~QQmlPropertyData::IsResettable;
+
+ QString propertyName = stringAt(p->nameIndex);
+ if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName;
+ propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
+ type, effectiveSignalIndex++);
+
+ }
+ }
+ return true;
+}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
new file mode 100644
index 0000000000..fe3a4bb00a
--- /dev/null
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** 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>
+#include <private/qqmlcompiler_p.h>
+#include <QLinkedList>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlAbstractBinding;
+
+struct QQmlCompilePass
+{
+ QQmlCompilePass(const QUrl &url, const QV4::CompiledData::QmlUnit *unit);
+ QList<QQmlError> errors;
+
+protected:
+ QString stringAt(int idx) const { return qmlUnit->header.stringAt(idx); }
+ void recordError(const QV4::CompiledData::Location &location, const QString &description);
+
+ const QUrl url;
+ const QV4::CompiledData::QmlUnit *qmlUnit;
+};
+
+class QQmlPropertyCacheCreator : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator)
+public:
+ QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QUrl &url, const QQmlImports *imports,
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes);
+
+ bool create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **cache, QByteArray *vmeMetaObjectData);
+
+protected:
+ QQmlEnginePrivate *enginePrivate;
+ const QQmlImports *imports;
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
+};
+
+class QQmlComponentAndAliasResolver : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
+public:
+ QQmlComponentAndAliasResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
+ const QList<QQmlPropertyCache *> &propertyCaches,
+ QList<QByteArray> *vmeMetaObjectData,
+ QHash<int, int> *objectIndexToIdForRoot,
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent);
+
+ bool resolve();
+
+ QVector<int> componentRoots;
+ QHash<int, int> objectIndexToComponentIndex;
+
+protected:
+ bool collectIdsAndAliases(int objectIndex);
+ bool resolveAliases();
+
+ int _componentIndex;
+ QHash<int, int> _idToObjectIndex;
+ QHash<int, int> *_objectIndexToIdInScope;
+ QList<int> _objectsWithAliases;
+
+ const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
+ const QList<QQmlPropertyCache *> propertyCaches;
+ QList<QByteArray> *vmeMetaObjectData;
+ QHash<int, int> *objectIndexToIdForRoot;
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
+};
+
+class QmlObjectCreator : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
+public:
+ QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData);
+
+ QObject *create(int subComponentIndex = -1, QObject *parent = 0);
+ void finalize();
+
+ QQmlComponentAttached *componentAttached;
+ QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
+
+private:
+ QObject *createInstance(int index, QObject *parent = 0);
+
+ bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *scopeObjectForJavaScript);
+
+ void setupBindings();
+ bool setPropertyValue(QQmlPropertyData *property, int index, const QV4::CompiledData::Binding *binding);
+ void setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
+ void setupFunctions();
+
+ QQmlEngine *engine;
+ const QV4::CompiledData::CompilationUnit *jsUnit;
+ QQmlContextData *parentContext;
+ QQmlContextData *context;
+ const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
+ const QList<QQmlPropertyCache *> propertyCaches;
+ const QList<QByteArray> vmeMetaObjectData;
+ QHash<int, int> objectIndexToId;
+ QLinkedList<QVector<QQmlAbstractBinding*> > allCreatedBindings;
+ QQmlCompiledData *compiledData;
+
+ QObject *_qobject;
+ const QV4::CompiledData::Object *_compiledObject;
+ QQmlData *_ddata;
+ QQmlRefPointer<QQmlPropertyCache> _propertyCache;
+ QQmlVMEMetaObject *_vmeMetaObject;
+ QVector<QQmlAbstractBinding*> _createdBindings;
+ QQmlListProperty<void> _currentList;
+ QV4::ExecutionContext *_qmlContext;
+};
+
+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..bc0cef9f4c 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -74,6 +74,7 @@ class QQmlAccessors;
class QMetaObjectBuilder;
class QQmlPropertyCacheMethodArguments;
class QQmlVMEMetaObject;
+class QQmlPropertyCacheCreator;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
@@ -339,6 +340,8 @@ protected:
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
+ friend class QQmlPropertyCacheCreator;
+ friend class QQmlComponentAndAliasResolver;
inline QQmlPropertyCache *copy(int reserve);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index a705e00886..27230cd669 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -49,6 +49,7 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlmemoryprofiler_p.h>
+#include <private/qqmlcodegenerator_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
@@ -1474,17 +1475,6 @@ QQmlImportDatabase *QQmlTypeLoader::importDatabase()
}
/*!
-\enum QQmlTypeLoader::Option
-
-This enum defines the options that control the way type data is handled.
-
-\value None The default value, indicating that no other options
- are enabled.
-\value PreserveParser The parser used to handle the type data is preserved
- after the data has been parsed.
-*/
-
-/*!
Returns a QQmlTypeData for the specified \a url. The QQmlTypeData may be cached.
*/
QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
@@ -1498,7 +1488,7 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
QQmlTypeData *typeData = m_typeCache.value(url);
if (!typeData) {
- typeData = new QQmlTypeData(url, None, this);
+ typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
QQmlDataLoader::load(typeData, mode);
@@ -1512,14 +1502,12 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
/*!
Returns a QQmlTypeData for the given \a data with the provided base \a url. The
QQmlTypeData will not be cached.
-
-The specified \a options control how the loader handles type data.
*/
-QQmlTypeData *QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url, Options options)
+QQmlTypeData *QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url)
{
LockHolder<QQmlTypeLoader> holder(this);
- QQmlTypeData *typeData = new QQmlTypeData(url, options, this);
+ QQmlTypeData *typeData = new QQmlTypeData(url, this);
QQmlDataLoader::loadWithStaticData(typeData, data);
return typeData;
@@ -1915,11 +1903,11 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback()
{
}
-QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader::Options options,
- QQmlTypeLoader *manager)
-: QQmlTypeLoader::Blob(url, QmlFile, manager), m_options(options),
+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()
@@ -1990,6 +1978,7 @@ void QQmlTypeData::done()
}
// Check all type dependencies for errors
+ // --- old compiler:
for (int ii = 0; !isError() && ii < m_types.count(); ++ii) {
const TypeReference &type = m_types.at(ii);
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
@@ -2006,13 +1995,32 @@ void QQmlTypeData::done()
setError(errors);
}
}
+ // --- new compiler:
+ for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
+ !isError() && it != end; ++it) {
+ const TypeReference &type = *it;
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ QString typeName = parsedQML->jsGenerator.strings.at(it.key());
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(finalUrl());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+ // ---
// Compile component
if (!isError())
compile();
- if (!(m_options & QQmlTypeLoader::PreserveParser))
- scriptParser.clear();
+ scriptParser.clear();
+ parsedQML.reset();
}
void QQmlTypeData::completed()
@@ -2052,9 +2060,18 @@ 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) {
+ parsedQML.reset(new QtQml::ParsedQML);
+ QQmlCodeGenerator compiler;
+ if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) {
+ setError(compiler.errors);
+ return;
+ }
+ } else {
+ if (!scriptParser.parse(code, preparseData, finalUrl(), finalUrlString())) {
+ setError(scriptParser.errors());
+ return;
+ }
}
m_imports.setBaseUrl(finalUrl(), finalUrlString());
@@ -2084,7 +2101,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());
@@ -2145,11 +2189,118 @@ 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) {
+ m_compiledData->importCache = new QQmlTypeNameCache;
+ m_imports.populateCache(m_compiledData->importCache);
+ m_compiledData->importCache->addref();
+
+ QQmlEngine *engine = typeLoader()->engine();
+
+ for (QHash<int, TypeReference>::ConstIterator resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
+ resolvedType != end; ++resolvedType) {
+ QQmlCompiledData::TypeReference ref;
+ if (resolvedType->typeData) {
+ ref.component = resolvedType->typeData->compiledData();
+ ref.component->addref();
+ } else {
+ ref.type = resolvedType->type;
+ Q_ASSERT(ref.type);
+ }
+ m_compiledData->resolvedTypes.insert(resolvedType.key(), ref);
+ }
+
+ {
+ SignalHandlerConverter converter(QQmlEnginePrivate::get(engine),
+ parsedQML.data(),
+ m_compiledData);
+ if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations()) {
+ setError(converter.errors);
+ m_compiledData->release();
+ m_compiledData = 0;
+ return;
+ }
+ }
+
+ JSCodeGen jsCodeGen;
+ jsCodeGen.generateJSCodeForFunctionsAndBindings(finalUrlString(), parsedQML.data());
+
+ 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.data());
+
+ if (jsUnit) {
+ Q_ASSERT(!jsUnit->data);
+ jsUnit->ownsData = false;
+ jsUnit->data = &qmlUnit->header;
+ }
+
+ m_compiledData->compilationUnit = jsUnit;
+ if (m_compiledData->compilationUnit)
+ m_compiledData->compilationUnit->ref();
+ m_compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData
+
+ QList<QQmlError> errors;
+
+ m_compiledData->datas.reserve(qmlUnit->nObjects);
+ m_compiledData->propertyCaches.reserve(qmlUnit->nObjects);
+
+ QQmlPropertyCacheCreator propertyCacheBuilder(QQmlEnginePrivate::get(m_typeLoader->engine()),
+ qmlUnit, m_compiledData->url,
+ &m_imports, &m_compiledData->resolvedTypes);
+
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+
+ QByteArray vmeMetaObjectData;
+ QQmlPropertyCache *propertyCache = 0;
+
+ // If the object has no type, then it's probably a nested object definition as part
+ // of a group property.
+ const bool objectHasType = !parsedQML->jsGenerator.strings.at(obj->inheritedTypeNameIndex).isEmpty();
+ if (objectHasType) {
+ if (!propertyCacheBuilder.create(obj, &propertyCache, &vmeMetaObjectData)) {
+ errors << propertyCacheBuilder.errors;
+ break;
+ }
+ }
+
+ m_compiledData->datas << vmeMetaObjectData;
+ if (propertyCache)
+ propertyCache->addref();
+ m_compiledData->propertyCaches << propertyCache;
+
+ if (i == qmlUnit->indexOfRootObject) {
+ Q_ASSERT(propertyCache);
+ m_compiledData->rootPropertyCache = propertyCache;
+ propertyCache->addref();
+ }
+ }
+
+ if (errors.isEmpty()) {
+ // Scan for components, determine their scopes and resolve aliases within the scope.
+ QQmlComponentAndAliasResolver resolver(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, m_compiledData->propertyCaches,
+ &m_compiledData->datas, &m_compiledData->objectIndexToIdForRoot, &m_compiledData->objectIndexToIdPerComponent);
+ if (!resolver.resolve())
+ errors << resolver.errors;
+ }
+
+ if (!errors.isEmpty()) {
+ setError(errors);
+ m_compiledData->release();
+ m_compiledData = 0;
+ }
+ } else {
+ QQmlCompiler compiler(&scriptParser._pool);
+ if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
+ setError(compiler.errors());
+ m_compiledData->release();
+ m_compiledData = 0;
+ }
}
}
@@ -2176,10 +2327,10 @@ void QQmlTypeData::resolveTypes()
m_scripts << ref;
}
+ // --- old compiler:
foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) {
TypeReference ref;
- QString url;
int majorVersion = -1;
int minorVersion = -1;
QQmlImportNamespace *typeNamespace = 0;
@@ -2239,6 +2390,80 @@ void QQmlTypeData::resolveTypes()
m_types << ref;
}
+
+ // --- new compiler:
+ QV4::CompiledData::TypeReferenceMap typeReferences;
+ QStringList names;
+ if (parsedQML) {
+ typeReferences = parsedQML->typeReferences;
+ names = parsedQML->jsGenerator.strings;
+ } else {
+ // ### collect from available QV4::CompiledData::QmlUnit
+ }
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = typeReferences.constBegin(), end = typeReferences.constEnd();
+ unresolvedRef != end; ++unresolvedRef) {
+
+ TypeReference ref; // resolved reference
+
+ int majorVersion = -1;
+ int minorVersion = -1;
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+
+ const QString name = names.at(unresolvedRef.key());
+ bool typeFound = m_imports.resolveType(name, &ref.type,
+ &majorVersion, &minorVersion, &typeNamespace, &errors);
+ if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
+ // Lazy loading of implicit import
+ if (loadImplicitImport()) {
+ // Try again to find the type
+ errors.clear();
+ typeFound = m_imports.resolveType(name, &ref.type,
+ &majorVersion, &minorVersion, &typeNamespace, &errors);
+ } else {
+ return; //loadImplicitImport() hit an error, and called setError already
+ }
+ }
+
+ if (!typeFound || typeNamespace) {
+ // Known to not be a type:
+ // - known to be a namespace (Namespace {})
+ // - type with unknown namespace (UnknownNamespace.SomeType {})
+ QQmlError error;
+ if (typeNamespace) {
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(name));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(name).arg(error.description()));
+ }
+
+ error.setLine(unresolvedRef->line);
+ error.setColumn(unresolvedRef->column);
+
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+
+ if (ref.type->isComposite()) {
+ ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
+ addDependency(ref.typeData);
+ }
+ ref.majorVersion = majorVersion;
+ ref.minorVersion = minorVersion;
+
+ ref.location.line = unresolvedRef->line;
+ ref.location.column = unresolvedRef->column;
+
+ m_resolvedTypes.insert(unresolvedRef.key(), ref);
+ }
}
void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 9ff7ddc0eb..fee09d3bdb 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -84,6 +84,10 @@ class QQmlTypeData;
class QQmlDataLoader;
class QQmlExtensionInterface;
+namespace QtQml {
+struct ParsedQML;
+}
+
class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
{
public:
@@ -323,16 +327,10 @@ public:
QQmlTypeLoader(QQmlEngine *);
~QQmlTypeLoader();
- enum Option {
- None,
- PreserveParser
- };
- Q_DECLARE_FLAGS(Options, Option)
-
QQmlImportDatabase *importDatabase();
QQmlTypeData *getType(const QUrl &url, Mode mode = PreferSynchronous);
- QQmlTypeData *getType(const QByteArray &, const QUrl &url, Options = None);
+ QQmlTypeData *getType(const QByteArray &, const QUrl &url);
QQmlScriptBlob *getScript(const QUrl &);
QQmlQmldirData *getQmldir(const QUrl &);
@@ -391,8 +389,6 @@ private:
QmldirBundleIdCache m_qmldirBundleIdCache;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlTypeLoader::Options)
-
class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
{
public:
@@ -419,7 +415,7 @@ public:
private:
friend class QQmlTypeLoader;
- QQmlTypeData(const QUrl &, QQmlTypeLoader::Options, QQmlTypeLoader *);
+ QQmlTypeData(const QUrl &, QQmlTypeLoader *);
public:
~QQmlTypeData();
@@ -454,16 +450,24 @@ private:
virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
- QQmlTypeLoader::Options m_options;
-
+ // --- old compiler
QQmlScript::Parser scriptParser;
+ // --- new compiler
+ QScopedPointer<QtQml::ParsedQML> parsedQML;
+ // ---
QList<ScriptReference> m_scripts;
QSet<QString> m_namespaces;
+ // --- old compiler
QList<TypeReference> m_types;
+ // --- new compiler
+ // map from name index to resolved type
+ QHash<int, TypeReference> m_resolvedTypes;
+ // ---
bool m_typesResolved:1;
+ bool m_useNewCompiler:1;
QQmlCompiledData *m_compiledData;
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index 244e0af4ac..fcf89afb9f 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -483,6 +483,10 @@ int main(int argc, char ** argv)
}
QObject *topLevel = component->create();
+ if (!topLevel && component->isError()) {
+ qWarning("%s", qPrintable(component->errorString()));
+ return -1;
+ }
QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(topLevel));
if (window) {
engine.setIncubationController(window->incubationController());