aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-20 19:30:06 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-20 19:30:06 +0200
commit60ecb7bfafe85736ab3294a3ba03255f6fdac257 (patch)
treef69a3c19cf795a94f110623d181fecb187a29169
parent59efbaac6838ff27fc56d4dd3f041b86ce44a6da (diff)
parent57919fe200c0ecbd4cf1873ed2c6c95732c2dd3b (diff)
Merge "Merge branch 'wip/v4' of qtdeclarative into dev" into refs/staging/dev
-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());