aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/compiler.pri6
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp108
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h16
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp1204
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h201
-rw-r--r--src/qml/compiler/qv4compileddata.cpp51
-rw-r--r--src/qml/compiler/qv4compileddata_p.h8
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp13
-rw-r--r--src/qml/compiler/qv4regalloc.cpp3
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp138
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h105
-rw-r--r--src/qml/jsapi/qjsvalue.cpp2
-rw-r--r--src/qml/jsruntime/jsruntime.pri2
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp40
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h5
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp563
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h242
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp195
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp17
-rw-r--r--src/qml/jsruntime/qv4context_p.h4
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp24
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp5
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp22
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp2
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp26
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp9
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h1
-rw-r--r--src/qml/jsruntime/qv4managed.cpp19
-rw-r--r--src/qml/jsruntime/qv4managed_p.h120
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4mm.cpp2
-rw-r--r--src/qml/jsruntime/qv4object.cpp635
-rw-r--r--src/qml/jsruntime/qv4object_p.h224
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp4
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp62
-rw-r--r--src/qml/jsruntime/qv4property_p.h2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp7
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp2
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h1
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp77
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp8
-rw-r--r--src/qml/jsruntime/qv4string.cpp18
-rw-r--r--src/qml/jsruntime/qv4string_p.h9
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp34
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4value_p.h4
-rw-r--r--src/qml/parser/qqmljsmemorypool_p.h2
-rw-r--r--src/qml/qml/qqmlbinding.cpp3
-rw-r--r--src/qml/qml/qqmlcompiler.cpp52
-rw-r--r--src/qml/qml/qqmlcompiler_p.h14
-rw-r--r--src/qml/qml/qqmlcomponent.cpp6
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp76
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h17
-rw-r--r--src/qml/qml/qqmlincubator.cpp17
-rw-r--r--src/qml/qml/qqmlincubator_p.h5
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp2
-rw-r--r--src/qml/qml/qqmllocale.cpp87
-rw-r--r--src/qml/qml/qqmllocale_p.h58
-rw-r--r--src/qml/qml/qqmlmetatype.cpp2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp1001
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h112
-rw-r--r--src/qml/qml/qqmlparserstatus.h1
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp2
-rw-r--r--src/qml/qml/qqmlscriptstring.h2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp176
-rw-r--r--src/qml/qml/qqmltypeloader_p.h5
-rw-r--r--src/qml/qml/v8/qv8engine.cpp41
-rw-r--r--src/qml/qml/v8/qv8engine_p.h4
-rw-r--r--src/qml/types/qqmlconnections.cpp38
-rw-r--r--src/qml/types/qqmlconnections_p.h1
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp62
-rw-r--r--src/qml/types/qqmllistmodel.cpp10
-rw-r--r--src/qml/types/qqmllistmodel_p.h4
-rw-r--r--src/qml/util/qqmladaptormodel.cpp7
86 files changed, 3764 insertions, 2345 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index df4f5e8dc3..b2569f9111 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -15,7 +15,8 @@ HEADERS += \
$$PWD/qv4ssa_p.h \
$$PWD/qv4regalloc_p.h \
$$PWD/qqmlcodegenerator_p.h \
- $$PWD/qv4isel_masm_p.h
+ $$PWD/qv4isel_masm_p.h \
+ $$PWD/qqmltypecompiler_p.h
SOURCES += \
$$PWD/qv4compileddata.cpp \
@@ -28,6 +29,7 @@ SOURCES += \
$$PWD/qv4ssa.cpp \
$$PWD/qv4regalloc.cpp \
$$PWD/qqmlcodegenerator.cpp \
- $$PWD/qv4isel_masm.cpp
+ $$PWD/qv4isel_masm.cpp \
+ $$PWD/qqmltypecompiler.cpp
include(../../3rdparty/masm/masm.pri)
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 13b23fde68..22ae1228c7 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -64,6 +64,21 @@ using namespace QtQml;
return false; \
}
+void QmlObject::init(MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &loc)
+{
+ inheritedTypeNameIndex = typeNameIndex;
+
+ location.line = loc.startLine;
+ location.column = loc.startColumn;
+
+ idIndex = id;
+ indexOfDefaultProperty = -1;
+ properties = pool->New<PoolList<QmlProperty> >();
+ qmlSignals = pool->New<PoolList<Signal> >();
+ bindings = pool->New<PoolList<Binding> >();
+ functions = pool->New<PoolList<Function> >();
+}
+
void QmlObject::dump(DebugStream &out)
{
out << inheritedTypeNameIndex << " {" << endl;
@@ -82,8 +97,9 @@ QStringList Signal::parameterStringList(const QStringList &stringPool) const
return result;
}
-QQmlCodeGenerator::QQmlCodeGenerator()
- : _object(0)
+QQmlCodeGenerator::QQmlCodeGenerator(const QSet<QString> &illegalNames)
+ : illegalNames(illegalNames)
+ , _object(0)
, jsGenerator(0)
{
}
@@ -214,7 +230,7 @@ bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node)
bool QQmlCodeGenerator::visit(AST::UiObjectBinding *node)
{
int idx = defineQMLObject(node->qualifiedTypeNameId, node->initializer);
- appendBinding(node->qualifiedId, idx);
+ appendBinding(node->qualifiedId, idx, node->hasOnToken);
return false;
}
@@ -292,10 +308,8 @@ bool QQmlCodeGenerator::sanityCheckFunctionNames()
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
+ if (illegalNames.contains(name))
+ COMPILE_EXCEPTION(function->identifierToken, tr("Illegal method name"));
}
return true;
}
@@ -307,20 +321,10 @@ int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId,
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> >();
+ _object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, loc);
QSet<QString> propertyNames;
qSwap(_propertyNames, propertyNames);
@@ -589,10 +593,8 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
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
+ if (illegalNames.contains(signalName))
+ COMPILE_EXCEPTION(node->identifierToken, tr("Illegal signal name"));
_object->qmlSignals->append(signal);
} else {
@@ -739,6 +741,10 @@ bool QQmlCodeGenerator::visit(AST::UiSourceElement *node)
if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
_functions << funDecl;
Function *f = New<Function>();
+ f->functionDeclaration = funDecl;
+ AST::SourceLocation loc = funDecl->firstSourceLocation();
+ f->location.line = loc.startLine;
+ f->location.column = loc.startColumn;
f->index = _functions.size() - 1;
_object->functions->append(f);
} else {
@@ -844,13 +850,13 @@ void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, AST::Statement *
qSwap(_object, object);
}
-void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, int objectIndex)
+void QQmlCodeGenerator::appendBinding(AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment)
{
QmlObject *object = 0;
if (!resolveQualifiedId(&name, &object))
return;
qSwap(_object, object);
- appendBinding(name->identifierToken, registerString(name->name.toString()), objectIndex);
+ appendBinding(name->identifierToken, registerString(name->name.toString()), objectIndex, /*isListItem*/false, isOnAssignment);
qSwap(_object, object);
}
@@ -873,9 +879,9 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i
_object->bindings->append(binding);
}
-void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem)
+void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
{
- if (!sanityCheckPropertyName(nameLocation, propertyNameIndex, isListItem))
+ if (!sanityCheckPropertyName(nameLocation, propertyNameIndex, isListItem | isOnAssignment))
return;
if (stringAt(propertyNameIndex) == QStringLiteral("id")) {
@@ -888,7 +894,16 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
binding->flags = 0;
- binding->type = QV4::CompiledData::Binding::Type_Object;
+
+ // No type name on the initializer means it must be a group property
+ if (stringAt(_objects.at(objectIndex)->inheritedTypeNameIndex).isEmpty())
+ binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ else
+ binding->type = QV4::CompiledData::Binding::Type_Object;
+
+ if (isOnAssignment)
+ binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+
binding->value.objectIndex = objectIndex;
_object->bindings->append(binding);
}
@@ -926,12 +941,11 @@ bool QQmlCodeGenerator::setId(AST::Statement *value)
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
+ QString idQString(str.toString());
+ if (illegalNames.contains(idQString))
+ COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property"));
- _object->idIndex = registerString(str.toString());
+ _object->idIndex = registerString(idQString);
_object->locationOfIdProperty.line = loc.startLine;
_object->locationOfIdProperty.column = loc.startColumn;
@@ -970,14 +984,14 @@ bool QQmlCodeGenerator::resolveQualifiedId(AST::UiQualifiedId **nameToResolve, Q
return true;
}
-bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItem)
+bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItemOnOrAssignment)
{
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 (!isListItemOnOrAssignment) {
if (_propertyNames.contains(name))
COMPILE_EXCEPTION(nameLocation, tr("Duplicate property name"));
@@ -987,13 +1001,8 @@ bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameL
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
+ if (illegalNames.contains(name))
+ COMPILE_EXCEPTION(nameLocation, tr("Illegal property name"));
return true;
}
@@ -1625,11 +1634,16 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate,
bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
{
- foreach (QmlObject *obj, parsedQML->objects) {
+ for (int objectIndex = 0; objectIndex < parsedQML->objects.count(); ++objectIndex) {
+ QmlObject * const obj = parsedQML->objects.at(objectIndex);
QString elementName = stringAt(obj->inheritedTypeNameIndex);
if (elementName.isEmpty())
continue;
- QQmlPropertyCache *cache = unit->resolvedTypes[obj->inheritedTypeNameIndex].createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ QQmlCompiledData::TypeReference &tr = unit->resolvedTypes[obj->inheritedTypeNameIndex];
+ if (tr.type && tr.type->customParser())
+ continue;
+ QQmlPropertyCache *cache = unit->propertyCaches.value(objectIndex);
+ Q_ASSERT(cache);
if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
return false;
}
@@ -1659,10 +1673,6 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (!QQmlCodeGenerator::isSignalPropertyName(propertyName))
continue;
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- COMPILE_EXCEPTION(binding->location, tr("Incorrectly specified signal assignment"));
- }
-
PropertyResolver resolver(propertyCache);
Q_ASSERT(propertyName.startsWith(QStringLiteral("on")));
@@ -1731,6 +1741,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
parameters = entry.value();
}
+ if (binding->type != QV4::CompiledData::Binding::Type_Script) {
+ COMPILE_EXCEPTION(binding->location, tr("Incorrectly specified signal assignment"));
+ }
+
QQmlJS::Engine &jsEngine = parsedQML->jsParserEngine;
QQmlJS::MemoryPool *pool = jsEngine.pool();
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 0a0e4f2d5b..f1050f4476 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -135,6 +135,8 @@ struct Binding : public QV4::CompiledData::Binding
struct Function
{
+ AST::FunctionDeclaration *functionDeclaration;
+ QV4::CompiledData::Location location;
int index; // index in parsedQML::functions
Function *next;
};
@@ -153,6 +155,8 @@ struct QmlObject
PoolList<Binding> *bindings;
PoolList<Function> *functions;
+ void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &location = AST::SourceLocation());
+
void dump(DebugStream &out);
};
@@ -207,7 +211,7 @@ struct Q_QML_EXPORT QQmlCodeGenerator : public AST::Visitor
{
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
- QQmlCodeGenerator();
+ QQmlCodeGenerator(const QSet<QString> &illegalNames);
bool generateFromQml(const QString &code, const QUrl &url, const QString &urlString, ParsedQML *output);
static bool isSignalPropertyName(const QString &name);
@@ -253,9 +257,9 @@ public:
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(AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false);
void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value);
- void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem = false);
+ void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
bool setId(AST::Statement *value);
@@ -263,7 +267,7 @@ public:
// 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);
+ bool sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItemOnOrAssignment = false);
void recordError(const AST::SourceLocation &location, const QString &description);
@@ -272,7 +276,7 @@ public:
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(); }
+ template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
QString stringAt(int index) const { return jsGenerator->strings.at(index); }
@@ -280,6 +284,8 @@ public:
QList<QQmlError> errors;
+ QSet<QString> illegalNames;
+
QList<QV4::CompiledData::Import*> _imports;
QList<Pragma*> _pragmas;
QList<QmlObject*> _objects;
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
new file mode 100644
index 0000000000..d6dde63d4b
--- /dev/null
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -0,0 +1,1204 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypecompiler_p.h"
+
+#include <private/qqmlcompiler_p.h>
+#include <private/qqmlobjectcreator_p.h>
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlcomponent_p.h>
+
+#define COMPILE_EXCEPTION(token, desc) \
+ { \
+ recordError((token)->location, desc); \
+ return false; \
+ }
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QtQml::ParsedQML *parsedQML)
+ : engine(engine)
+ , compiledData(compiledData)
+ , typeData(typeData)
+ , parsedQML(parsedQML)
+{
+}
+
+bool QQmlTypeCompiler::compile()
+{
+ compiledData->importCache = new QQmlTypeNameCache;
+
+ foreach (const QString &ns, typeData->namespaces())
+ compiledData->importCache->add(ns);
+
+ // Add any Composite Singletons that were used to the import cache
+ foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons())
+ compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
+
+ typeData->imports().populateCache(compiledData->importCache);
+ compiledData->importCache->addref();
+
+ const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs();
+ for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
+ resolvedType != end; ++resolvedType) {
+ QQmlCompiledData::TypeReference ref;
+ if (resolvedType->typeData) {
+ ref.component = resolvedType->typeData->compiledData();
+ ref.component->addref();
+ } else {
+ ref.type = resolvedType->type;
+ Q_ASSERT(ref.type);
+ }
+ ref.majorVersion = resolvedType->majorVersion;
+ ref.minorVersion = resolvedType->minorVersion;
+ compiledData->resolvedTypes.insert(resolvedType.key(), ref);
+ }
+
+ // Build property caches and VME meta object data
+
+ const int objectCount = parsedQML->objects.count();
+ compiledData->datas.reserve(objectCount);
+ compiledData->propertyCaches.reserve(objectCount);
+
+ {
+ QQmlPropertyCacheCreator propertyCacheBuilder(this);
+ if (!propertyCacheBuilder.buildMetaObjects())
+ return false;
+ }
+
+ {
+ SignalHandlerConverter converter(engine, parsedQML, compiledData);
+ if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations()) {
+ errors << converter.errors;
+ return false;
+ }
+ }
+
+ // Collect imported scripts
+ const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts();
+ compiledData->scripts.reserve(scripts.count());
+ for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) {
+ const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
+
+ QString qualifier = script.qualifier;
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex);
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
+
+ compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace);
+ QQmlScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ compiledData->scripts << scriptData;
+ }
+
+ // Resolve component boundaries and aliases
+
+ {
+ // Scan for components, determine their scopes and resolve aliases within the scope.
+ QQmlComponentAndAliasResolver resolver(this);
+ if (!resolver.resolve())
+ return false;
+ }
+
+ // Compile JS binding expressions and signal handlers
+
+ JSCodeGen jsCodeGen(typeData->finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, compiledData->importCache);
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
+
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
+ isel->setUseFastLookups(false);
+ QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
+
+ // Generate QML compiled type data structures
+
+ QmlUnitGenerator qmlGenerator;
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML, runtimeFunctionIndices);
+
+ if (jsUnit) {
+ Q_ASSERT(!jsUnit->data);
+ jsUnit->ownsData = false;
+ jsUnit->data = &qmlUnit->header;
+ }
+
+ compiledData->compilationUnit = jsUnit;
+ if (compiledData->compilationUnit)
+ compiledData->compilationUnit->ref();
+ compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData
+
+ // Add to type registry of composites
+ if (compiledData->isCompositeType())
+ engine->registerInternalCompositeType(compiledData);
+ else {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
+ QQmlCompiledData::TypeReference typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex);
+ if (typeRef.component) {
+ compiledData->metaTypeId = typeRef.component->metaTypeId;
+ compiledData->listMetaTypeId = typeRef.component->listMetaTypeId;
+ } else {
+ compiledData->metaTypeId = typeRef.type->typeId();
+ compiledData->listMetaTypeId = typeRef.type->qListTypeId();
+ }
+ }
+
+ // Sanity check property bindings
+ QQmlPropertyValidator validator(this);
+ if (!validator.validate())
+ return false;
+
+ return errors.isEmpty();
+}
+
+void QQmlTypeCompiler::recordError(const QQmlError &error)
+{
+ QQmlError e = error;
+ e.setUrl(compiledData->url);
+ errors << e;
+}
+
+QString QQmlTypeCompiler::stringAt(int idx) const
+{
+ return parsedQML->stringAt(idx);
+}
+
+int QQmlTypeCompiler::registerString(const QString &str)
+{
+ return parsedQML->jsGenerator.registerString(str);
+}
+
+const QV4::CompiledData::QmlUnit *QQmlTypeCompiler::qmlUnit() const
+{
+ return compiledData->qmlUnit;
+}
+
+const QQmlImports *QQmlTypeCompiler::imports() const
+{
+ return &typeData->imports();
+}
+
+QHash<int, QQmlCompiledData::TypeReference> *QQmlTypeCompiler::resolvedTypes()
+{
+ return &compiledData->resolvedTypes;
+}
+
+QList<QmlObject *> *QQmlTypeCompiler::qmlObjects()
+{
+ return &parsedQML->objects;
+}
+
+int QQmlTypeCompiler::rootObjectIndex() const
+{
+ return parsedQML->indexOfRootObject;
+}
+
+void QQmlTypeCompiler::setPropertyCaches(const QVector<QQmlPropertyCache *> &caches)
+{
+ Q_ASSERT(compiledData->propertyCaches.isEmpty());
+ compiledData->propertyCaches = caches;
+ Q_ASSERT(caches.count() >= parsedQML->indexOfRootObject);
+ compiledData->rootPropertyCache = caches.at(parsedQML->indexOfRootObject);
+}
+
+const QVector<QQmlPropertyCache *> &QQmlTypeCompiler::propertyCaches() const
+{
+ return compiledData->propertyCaches;
+}
+
+void QQmlTypeCompiler::setVMEMetaObjects(const QVector<QByteArray> &metaObjects)
+{
+ Q_ASSERT(compiledData->datas.isEmpty());
+ compiledData->datas = metaObjects;
+}
+
+QVector<QByteArray> *QQmlTypeCompiler::vmeMetaObjects() const
+{
+ return &compiledData->datas;
+}
+
+QHash<int, int> *QQmlTypeCompiler::objectIndexToIdForRoot()
+{
+ return &compiledData->objectIndexToIdForRoot;
+}
+
+QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent()
+{
+ return &compiledData->objectIndexToIdPerComponent;
+}
+
+QHash<int, QByteArray> *QQmlTypeCompiler::customParserData()
+{
+ return &compiledData->customParserData;
+}
+
+MemoryPool *QQmlTypeCompiler::memoryPool()
+{
+ return parsedQML->jsParserEngine.pool();
+}
+
+QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
+ : compiler(typeCompiler)
+{
+}
+
+void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description)
+{
+ QQmlError error;
+ error.setLine(location.line);
+ error.setColumn(location.column);
+ error.setDescription(description);
+ compiler->recordError(error);
+}
+
+static QAtomicInt classIndexCounter(0);
+
+QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , enginePrivate(typeCompiler->enginePrivate())
+ , qmlObjects(*typeCompiler->qmlObjects())
+ , imports(typeCompiler->imports())
+ , resolvedTypes(typeCompiler->resolvedTypes())
+{
+}
+
+QQmlPropertyCacheCreator::~QQmlPropertyCacheCreator()
+{
+ for (int i = 0; i < propertyCaches.count(); ++i)
+ if (QQmlPropertyCache *cache = propertyCaches.at(i))
+ cache->release();
+ propertyCaches.clear();
+}
+
+bool QQmlPropertyCacheCreator::buildMetaObjects()
+{
+ propertyCaches.resize(qmlObjects.count());
+ vmeMetaObjects.resize(qmlObjects.count());
+
+ if (!buildMetaObjectRecursively(compiler->rootObjectIndex(), /*referencing object*/-1, /*instantiating binding*/0))
+ return false;
+
+ compiler->setVMEMetaObjects(vmeMetaObjects);
+ compiler->setPropertyCaches(propertyCaches);
+ propertyCaches.clear();
+
+ return true;
+}
+
+bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding)
+{
+ const QmlObject *obj = qmlObjects.at(objectIndex);
+
+ QQmlPropertyCache *baseTypeCache = 0;
+
+ bool needVMEMetaObject = obj->properties->count != 0 || obj->qmlSignals->count != 0 || obj->functions->count != 0;
+ if (!needVMEMetaObject) {
+ for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+
+ // On assignments are implemented using value interceptors, which require a VME meta object.
+ needVMEMetaObject = true;
+
+ // If the on assignment is inside a group property, we need to distinguish between QObject based
+ // group properties and value type group properties. For the former the base type is derived from
+ // the property that references us, for the latter we only need a meta-object on the referencing object
+ // because interceptors can't go to the shared value type instances.
+ if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex);
+ Q_ASSERT(parentCache);
+ Q_ASSERT(!stringAt(instantiatingBinding->propertyNameIndex).isEmpty());
+
+ bool notInRevision = false;
+ QQmlPropertyData *pd = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
+ Q_ASSERT(pd);
+ if (QQmlValueTypeFactory::isValueType(pd->propType)) {
+ needVMEMetaObject = false;
+ if (!ensureMetaObject(referencingObjectIndex))
+ return false;
+ } else if (pd->isQObject()) {
+ baseTypeCache = enginePrivate->rawPropertyCacheForType(pd->propType);
+ Q_ASSERT(baseTypeCache);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ QString typeName = stringAt(obj->inheritedTypeNameIndex);
+ if (!typeName.isEmpty()) {
+ QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ Q_ASSERT(baseTypeCache);
+ }
+
+ if (needVMEMetaObject) {
+ if (!createMetaObject(objectIndex, obj, baseTypeCache))
+ return false;
+ } else if (baseTypeCache) {
+ propertyCaches[objectIndex] = baseTypeCache;
+ baseTypeCache->addref();
+ }
+
+ for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next)
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object)
+ if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding))
+ return false;
+
+ return true;
+}
+
+bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex)
+{
+ if (!vmeMetaObjects.at(objectIndex).isEmpty())
+ return true;
+ const QtQml::QmlObject *obj = qmlObjects.at(objectIndex);
+ QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ return createMetaObject(objectIndex, obj, baseTypeCache);
+}
+
+bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::QmlObject *obj, QQmlPropertyCache *baseTypeCache)
+{
+ QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate),
+ obj->properties->count,
+ obj->functions->count + obj->properties->count + obj->qmlSignals->count,
+ obj->qmlSignals->count + obj->properties->count);
+ propertyCaches[objectIndex] = cache;
+ cache->addref();
+
+ struct TypeData {
+ QV4::CompiledData::Property::Type dtype;
+ int metaType;
+ } builtinTypes[] = {
+ { QV4::CompiledData::Property::Var, qMetaTypeId<QJSValue>() },
+ { 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;
+
+ for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next) {
+ 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 = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData)
+ + obj->properties->count * sizeof(VMD::PropertyData)
+ + obj->functions->count * 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;
+
+ for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next) {
+ 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 (QtQml::Signal *s = obj->qmlSignals->first; s; s = s->next) {
+ const int paramCount = s->parameters->count;
+
+ QList<QByteArray> names;
+ QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
+
+ if (paramCount) {
+ paramTypes[0] = paramCount;
+
+ QtQml::SignalParameter *param = s->parameters->first;
+ for (int i = 0; i < paramCount; ++i, param = param->next) {
+ 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
+ for (QtQml::Function *s = obj->functions->first; s; s = s->next) {
+ AST::FunctionDeclaration *astFunction = s->functionDeclaration;
+
+ quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
+
+ if (astFunction->formals)
+ flags |= QQmlPropertyData::HasArguments;
+
+ QString slotName = astFunction->name.toString();
+ 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.
+
+ QList<QByteArray> parameterNames;
+ AST::FormalParameterList *param = astFunction->formals;
+ while (param) {
+ parameterNames << param->name.toUtf8();
+ param = param->next;
+ }
+
+ cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
+ }
+
+
+ // Dynamic properties (except var and aliases)
+ int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
+ int propertyIdx = 0;
+ for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next, ++propertyIdx) {
+
+ 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 (propertyIdx == 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
+ propertyIdx = 0;
+ for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next, ++propertyIdx) {
+
+ 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 (propertyIdx == 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
+ for (QtQml::Function *s = obj->functions->first; s; s = s->next) {
+ AST::FunctionDeclaration *astFunction = s->functionDeclaration;
+ int formalsCount = 0;
+ AST::FormalParameterList *param = astFunction->formals;
+ while (param) {
+ formalsCount++;
+ param = param->next;
+ }
+
+ VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ###
+ formalsCount,
+ /* s->location.start.line */0 }; // ###
+
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
+ vmd->methodCount++;
+ md = methodData;
+ }
+
+ return true;
+}
+
+QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , enginePrivate(typeCompiler->enginePrivate())
+ , pool(typeCompiler->memoryPool())
+ , qmlObjects(typeCompiler->qmlObjects())
+ , indexOfRootObject(typeCompiler->rootObjectIndex())
+ , _componentIndex(-1)
+ , _objectIndexToIdInScope(0)
+ , resolvedTypes(typeCompiler->resolvedTypes())
+ , propertyCaches(typeCompiler->propertyCaches())
+ , vmeMetaObjectData(typeCompiler->vmeMetaObjects())
+ , objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot())
+ , objectIndexToIdPerComponent(typeCompiler->objectIndexToIdPerComponent())
+{
+}
+
+void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, int objectIndex)
+{
+ QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex);
+ Q_ASSERT(propertyCache);
+
+ PropertyResolver propertyResolver(propertyCache);
+
+ bool defaultPropertyQueried = false;
+ QQmlPropertyData *defaultProperty = 0;
+
+ for (QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ continue;
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ continue;
+
+ const QtQml::QmlObject *targetObject = qmlObjects->at(binding->value.objectIndex);
+ QQmlType *targetType = resolvedTypes->value(targetObject->inheritedTypeNameIndex).type;
+ if (targetType && targetType->metaObject() == &QQmlComponent::staticMetaObject)
+ continue;
+
+ QQmlPropertyData *pd = 0;
+ QString propertyName = stringAt(binding->propertyNameIndex);
+ if (!propertyName.isEmpty()) {
+ bool notInRevision = false;
+ pd = propertyResolver.property(propertyName, &notInRevision);
+ } else {
+ if (!defaultPropertyQueried) {
+ defaultProperty = propertyCache->defaultProperty();
+ defaultPropertyQueried = true;
+ }
+ pd = defaultProperty;
+ }
+ if (!pd || !pd->isQObject())
+ continue;
+
+ QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType);
+ const QMetaObject *mo = pc->firstCppMetaObject();
+ while (mo) {
+ if (mo == &QQmlComponent::staticMetaObject)
+ break;
+ mo = mo->superClass();
+ }
+
+ if (!mo)
+ continue;
+
+ static QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
+ Q_ASSERT(componentType);
+
+ QtQml::QmlObject *syntheticComponent = pool->New<QtQml::QmlObject>();
+ syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
+
+ if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
+ QQmlCompiledData::TypeReference typeRef;
+ typeRef.type = componentType;
+ typeRef.majorVersion = componentType->majorVersion();
+ typeRef.minorVersion = componentType->minorVersion();
+ resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
+ }
+
+ qmlObjects->append(syntheticComponent);
+ const int componentIndex = qmlObjects->count() - 1;
+
+ QtQml::Binding *syntheticBinding = pool->New<QtQml::Binding>();
+ *syntheticBinding = *binding;
+ syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
+ syntheticComponent->bindings->append(syntheticBinding);
+
+ binding->value.objectIndex = componentIndex;
+
+ componentRoots.append(componentIndex);
+ componentBoundaries.append(syntheticBinding->value.objectIndex);
+ }
+}
+
+bool QQmlComponentAndAliasResolver::resolve()
+{
+ // Detect real Component {} objects as well as implicitly defined components, such as
+ // someItemDelegate: Item {}
+ // In the implicit case Item is surrounded by a synthetic Component {} because the property
+ // on the left hand side is of QQmlComponent type.
+ for (int i = 0; i < qmlObjects->count(); ++i) {
+ const QtQml::QmlObject *obj = qmlObjects->at(i);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ continue;
+
+ QQmlCompiledData::TypeReference tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
+ if (!tref.type)
+ continue;
+ if (tref.type->metaObject() != &QQmlComponent::staticMetaObject) {
+ findAndRegisterImplicitComponents(obj, i);
+ continue;
+ }
+
+ componentRoots.append(i);
+
+ if (obj->functions->count > 0)
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
+ if (obj->properties->count > 0)
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
+ if (obj->qmlSignals->count > 0)
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
+
+ if (obj->bindings->count == 0)
+ COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
+
+ const QtQml::Binding *rootBinding = obj->bindings->first;
+ if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
+ COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
+
+ componentBoundaries.append(rootBinding->value.objectIndex);
+ }
+
+ std::sort(componentBoundaries.begin(), componentBoundaries.end());
+
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ const QtQml::QmlObject *component = qmlObjects->at(componentRoots.at(i));
+ const QtQml::Binding *rootBinding = component->bindings->first;
+
+ _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(indexOfRootObject);
+
+ resolveAliases();
+
+ return true;
+}
+
+bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
+{
+ const QtQml::QmlObject *obj = qmlObjects->at(objectIndex);
+
+ 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());
+ }
+
+ for (QtQml::QmlProperty *property = obj->properties->first; property; property = property->next) {
+ if (property->type == QV4::CompiledData::Property::Alias) {
+ _objectsWithAliases.append(objectIndex);
+ break;
+ }
+ }
+
+ for (QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ 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(componentBoundaries.constBegin(), componentBoundaries.constEnd(), binding->value.objectIndex))
+ continue;
+
+ if (!collectIdsAndAliases(binding->value.objectIndex))
+ return false;
+ }
+
+ return true;
+}
+
+bool QQmlComponentAndAliasResolver::resolveAliases()
+{
+ foreach (int objectIndex, _objectsWithAliases) {
+ const QtQml::QmlObject *obj = qmlObjects->at(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 QtQml::QmlProperty *p = obj->properties->first;
+ for (int propertyIndex = 0; propertyIndex < obj->properties->count; ++propertyIndex, p = p->next) {
+ if (p->type != QV4::CompiledData::Property::Alias)
+ continue;
+
+ const int idIndex = p->aliasIdValueIndex;
+ const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
+ if (targetObjectIndex == -1) {
+ recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ return false;
+ }
+ 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 QtQml::QmlObject *targetObject = qmlObjects->at(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) {
+ recordError(p->aliasLocation, tr("Invalid alias location"));
+ return false;
+ }
+
+ 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) {
+ recordError(p->aliasLocation, tr("Invalid alias location"));
+ return false;
+ }
+
+ propType = type;
+
+ int valueTypeIndex =
+ valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1) {
+ recordError(p->aliasLocation, tr("Invalid alias location"));
+ return false;
+ }
+ 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;
+}
+
+
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
+ : QQmlCompilePass(typeCompiler)
+ , qmlUnit(typeCompiler->qmlUnit())
+ , resolvedTypes(*typeCompiler->resolvedTypes())
+ , propertyCaches(typeCompiler->propertyCaches())
+ , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
+ , customParserData(typeCompiler->customParserData())
+{
+}
+
+bool QQmlPropertyValidator::validate()
+{
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ continue;
+
+ if (isComponent(i))
+ continue;
+
+ QQmlPropertyCache *propertyCache = propertyCaches.value(i);
+ Q_ASSERT(propertyCache);
+
+ if (!validateObject(obj, i, propertyCache))
+ return false;
+ }
+ return true;
+}
+
+const QQmlImports &QQmlPropertyValidator::imports() const
+{
+ return *compiler->imports();
+}
+
+bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache)
+{
+ QQmlCustomParser *customParser = 0;
+ QQmlCompiledData::TypeReference objectType = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ if (objectType.type)
+ customParser = objectType.type->customParser();
+ QList<const QV4::CompiledData::Binding*> customBindings;
+
+ PropertyResolver propertyResolver(propertyCache);
+
+ QQmlPropertyData *defaultProperty = propertyCache->defaultProperty();
+
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
+ || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ if (customParser)
+ customBindings << binding;
+ continue;
+ }
+
+ const QString name = stringAt(binding->propertyNameIndex);
+
+ bool bindingToDefaultProperty = false;
+
+ bool notInRevision = false;
+ QQmlPropertyData *pd = 0;
+ if (!name.isEmpty()) {
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ pd = propertyResolver.signal(name, &notInRevision);
+ else
+ pd = propertyResolver.property(name, &notInRevision);
+
+ if (notInRevision) {
+ QString typeName = stringAt(obj->inheritedTypeNameIndex);
+ if (objectType.type) {
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType.type->module()).arg(objectType.majorVersion).arg(objectType.minorVersion));
+ } else {
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
+ }
+ }
+ } else {
+ pd = defaultProperty;
+ bindingToDefaultProperty = true;
+ }
+
+ if (!pd) {
+ if (customParser) {
+ customBindings << binding;
+ continue;
+ }
+ if (bindingToDefaultProperty) {
+ COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
+ } else {
+ COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
+ }
+ }
+ }
+
+ if (customParser && !customBindings.isEmpty()) {
+ customParser->clearErrors();
+ customParser->compiler = this;
+ QByteArray data = customParser->compile(qmlUnit, customBindings);
+ customParser->compiler = 0;
+ customParserData->insert(objectIndex, data);
+ const QList<QQmlError> parserErrors = customParser->errors();
+ if (!parserErrors.isEmpty()) {
+ foreach (QQmlError error, parserErrors)
+ compiler->recordError(error);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
new file mode 100644
index 0000000000..248cd12796
--- /dev/null
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLTYPECOMPILER_P_H
+#define QQMLTYPECOMPILER_P_H
+
+#include <qglobal.h>
+#include <qqmlerror.h>
+#include <qhash.h>
+#include <private/qqmlcompiler_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEnginePrivate;
+class QQmlCompiledData;
+class QQmlError;
+class QQmlTypeData;
+class QQmlImports;
+
+namespace QtQml {
+struct ParsedQML;
+}
+
+namespace QV4 {
+namespace CompiledData {
+struct QmlUnit;
+struct Location;
+}
+}
+
+struct QQmlTypeCompiler
+{
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QtQml::ParsedQML *parsedQML);
+
+ bool compile();
+
+ QList<QQmlError> compilationErrors() const { return errors; }
+ void recordError(const QQmlError &error);
+
+ QString stringAt(int idx) const;
+ int registerString(const QString &str);
+
+ const QV4::CompiledData::QmlUnit *qmlUnit() const;
+
+ QQmlEnginePrivate *enginePrivate() const { return engine; }
+ const QQmlImports *imports() const;
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes();
+ QList<QtQml::QmlObject*> *qmlObjects();
+ int rootObjectIndex() const;
+ void setPropertyCaches(const QVector<QQmlPropertyCache *> &caches);
+ const QVector<QQmlPropertyCache *> &propertyCaches() const;
+ void setVMEMetaObjects(const QVector<QByteArray> &metaObjects);
+ QVector<QByteArray> *vmeMetaObjects() const;
+ QHash<int, int> *objectIndexToIdForRoot();
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
+ QHash<int, QByteArray> *customParserData();
+ QQmlJS::MemoryPool *memoryPool();
+
+private:
+ QList<QQmlError> errors;
+ QQmlEnginePrivate *engine;
+ QQmlCompiledData *compiledData;
+ QQmlTypeData *typeData;
+ QtQml::ParsedQML *parsedQML;
+};
+
+struct QQmlCompilePass
+{
+ virtual ~QQmlCompilePass() {}
+
+ QQmlCompilePass(QQmlTypeCompiler *typeCompiler);
+
+ QString stringAt(int idx) const { return compiler->stringAt(idx); }
+protected:
+ void recordError(const QV4::CompiledData::Location &location, const QString &description);
+
+ QQmlTypeCompiler *compiler;
+};
+
+class QQmlPropertyCacheCreator : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator)
+public:
+ QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler);
+ ~QQmlPropertyCacheCreator();
+
+ bool buildMetaObjects();
+protected:
+ bool buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding);
+ bool ensureMetaObject(int objectIndex);
+ bool createMetaObject(int objectIndex, const QtQml::QmlObject *obj, QQmlPropertyCache *baseTypeCache);
+
+ QQmlEnginePrivate *enginePrivate;
+ const QList<QtQml::QmlObject*> &qmlObjects;
+ const QQmlImports *imports;
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
+ QVector<QByteArray> vmeMetaObjects;
+ QVector<QQmlPropertyCache*> propertyCaches;
+};
+
+class QQmlComponentAndAliasResolver : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
+public:
+ QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler);
+
+ bool resolve();
+
+protected:
+ void findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, int objectIndex);
+ bool collectIdsAndAliases(int objectIndex);
+ bool resolveAliases();
+
+ QQmlEnginePrivate *enginePrivate;
+ QQmlJS::MemoryPool *pool;
+
+ QList<QtQml::QmlObject*> *qmlObjects;
+ const int indexOfRootObject;
+
+ // indices of the objects that are actually Component {}
+ QVector<int> componentRoots;
+ // indices of objects that are the beginning of a new component
+ // scope. This is sorted and used for binary search.
+ QVector<int> componentBoundaries;
+
+ int _componentIndex;
+ QHash<int, int> _idToObjectIndex;
+ QHash<int, int> *_objectIndexToIdInScope;
+ QList<int> _objectsWithAliases;
+
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
+ const QVector<QQmlPropertyCache *> propertyCaches;
+ QVector<QByteArray> *vmeMetaObjectData;
+ QHash<int, int> *objectIndexToIdForRoot;
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
+};
+
+class QQmlPropertyValidator : public QQmlCompilePass, public QQmlCustomParserCompilerBackend
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
+public:
+ QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler);
+
+ bool validate();
+
+ // Re-implemented for QQmlCustomParser
+ virtual const QQmlImports &imports() const;
+
+
+private:
+ bool validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache);
+
+ bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
+
+ const QV4::CompiledData::QmlUnit *qmlUnit;
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes;
+ const QVector<QQmlPropertyCache *> &propertyCaches;
+ const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
+ QHash<int, QByteArray> *customParserData;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPECOMPILER_P_H
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index ce0c7abf9e..9eac0e678d 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -193,6 +193,57 @@ QString Binding::valueAsString(const Unit *unit) const
return QString();
}
+//reverse of Lexer::singleEscape()
+static QString escapedString(const QString &string)
+{
+ QString tmp = QLatin1String("\"");
+ for (int i = 0; i < string.length(); ++i) {
+ const QChar &c = string.at(i);
+ switch (c.unicode()) {
+ case 0x08:
+ tmp += QLatin1String("\\b");
+ break;
+ case 0x09:
+ tmp += QLatin1String("\\t");
+ break;
+ case 0x0A:
+ tmp += QLatin1String("\\n");
+ break;
+ case 0x0B:
+ tmp += QLatin1String("\\v");
+ break;
+ case 0x0C:
+ tmp += QLatin1String("\\f");
+ break;
+ case 0x0D:
+ tmp += QLatin1String("\\r");
+ break;
+ case 0x22:
+ tmp += QLatin1String("\\\"");
+ break;
+ case 0x27:
+ tmp += QLatin1String("\\\'");
+ break;
+ case 0x5C:
+ tmp += QLatin1String("\\\\");
+ break;
+ default:
+ tmp += c;
+ break;
+ }
+ }
+ tmp += QLatin1Char('\"');
+ return tmp;
+}
+
+QString Binding::valueAsScriptString(const Unit *unit) const
+{
+ if (type == Type_String)
+ return escapedString(unit->stringAt(stringIndex));
+ else
+ return valueAsString(unit);
+}
+
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 90f27d5f57..f9e85ef080 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -264,7 +264,7 @@ struct Function
// Qml data structures
-struct Binding
+struct Q_QML_EXPORT Binding
{
quint32 propertyNameIndex;
@@ -280,7 +280,8 @@ struct Binding
};
enum Flags {
- IsSignalHandlerExpression = 0x1
+ IsSignalHandlerExpression = 0x1,
+ IsOnAssignment = 0x2
};
quint32 flags : 16;
@@ -296,6 +297,7 @@ struct Binding
Location location;
QString valueAsString(const Unit *unit) const;
+ QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const
{
if (type == Type_Number)
@@ -516,6 +518,8 @@ protected:
}
+Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
+
QT_END_NAMESPACE
#endif
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 35097bae49..415fdad8e9 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -1015,7 +1015,7 @@ void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *ta
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
-#if QT_POINTER_SIZE == 8
+#if 0 // QT_POINTER_SIZE == 8
V4IR::Temp *tbase = base->asTemp();
V4IR::Temp *tindex = index->asTemp();
if (tbase && tindex &&
@@ -1026,9 +1026,10 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
_as->urshift64(Assembler::TrustedImm32(QV4::Value::IsManaged_Shift), Assembler::ReturnValueRegister);
Assembler::Jump notManaged = _as->branch64(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm64(0));
// check whether we have an object with a simple array
- Assembler::Address managedType(Assembler::ScratchRegister, qOffsetOf(QV4::Managed, flags));
+ // ### need to check we have an object first!
+ Assembler::Address managedType(Assembler::ScratchRegister, qOffsetOf(QV4::Object, arrayData) + qOffsetOf(QV4::ArrayData, flags));
_as->load8(managedType, Assembler::ReturnValueRegister);
- _as->and32(Assembler::TrustedImm32(QV4::Managed::SimpleArray), Assembler::ReturnValueRegister);
+ _as->and32(Assembler::TrustedImm32(QV4::ArrayData::SimpleArray), Assembler::ReturnValueRegister);
Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
bool needNegativeCheck = false;
@@ -1069,12 +1070,12 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR:
// get data, ScratchRegister holds index
addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase);
_as->load64(addr, Assembler::ReturnValueRegister);
- Address arrayDataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayDataLen));
+ Address dataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData) + qOffsetOf(ArrayData, length));
Assembler::Jump outOfRange;
if (needNegativeCheck)
outOfRange = _as->branch32(Assembler::LessThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
- Assembler::Jump outOfRange2 = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen);
- Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData));
+ Assembler::Jump outOfRange2 = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, dataLen);
+ Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData) + qOffsetOf(ArrayData, data));
_as->load64(arrayData, Assembler::ReturnValueRegister);
Q_ASSERT(sizeof(Property) == (1<<4));
_as->lshift64(Assembler::TrustedImm32(4), Assembler::ScratchRegister);
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 048aad8497..f95cd55b04 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -60,6 +60,9 @@ struct Use {
}
QT_BEGIN_NAMESPACE
+
+Q_DECLARE_TYPEINFO(Use, Q_MOVABLE_TYPE);
+
using namespace QQmlJS::V4IR;
namespace QQmlJS {
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
index af2aea21ae..03bf464542 100644
--- a/src/qml/debugger/qqmlprofilerservice.cpp
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -131,6 +131,7 @@ QQmlProfilerService::QQmlProfilerService()
QQmlProfilerService::~QQmlProfilerService()
{
+ enabled = false;
instance = 0;
}
@@ -426,153 +427,68 @@ void QQmlProfilerService::messageReceived(const QByteArray &message)
}
/*!
- * \brief QQmlVmeProfiler::Data::clear Reset to defaults
- * Reset the profiling data to defaults.
+ * \fn void QQmlVmeProfiler::Data::clear()
+ * Resets the profiling data to defaults.
*/
-void QQmlVmeProfiler::Data::clear()
-{
- url.clear();
- line = 0;
- column = 0;
- typeName.clear();
-}
/*!
- * \brief QQmlVmeProfiler::start Start profiler without data
+ * \fn bool QQmlVmeProfiler::start()
* Clears the current range data, then stops the profiler previously running in the
- * foreground if any, then starts a new one.
+ * foreground if any, then starts a new one if profiling is enabled.
+ * Returns whether the new profiler was actually started.
*/
-bool QQmlVmeProfiler::start()
-{
- if (QQmlProfilerService::enabled) {
- currentRange.clear();
- if (running)
- QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
- else
- running = true;
- QQmlProfilerService::instance->startRange(QQmlProfilerService::Creating);
- return true;
- }
- return false;
-}
/*!
- * \brief QQmlVmeProfiler::updateLocation Update current location information
- * \param url URL of file being executed
- * \param line line Curent line in file
- * \param column column Current column in file
- * Updates the current profiler's location information.
+ * \fn void QQmlVmeProfiler::updateLocation(const QUrl &url, int line, int column)
+ * Updates the current profiler's location information. \a url is the URL of
+ * file being executed, \line line is the current line in in that file, and
+ * \a column is the current column in that file.
*/
-void QQmlVmeProfiler::updateLocation(const QUrl &url, int line, int column)
-{
- if (QQmlProfilerService::enabled && running) {
- currentRange.url = url;
- currentRange.line = line;
- currentRange.column = column;
- QQmlProfilerService::instance->rangeLocation(
- QQmlProfilerService::Creating, url, line, column);
- }
-}
/*!
- * \brief QQmlVmeProfiler::updateTypeName Update current type information
- * \param typeName Type of object being created
- * Updates the current profiler's type information.
+ * \fn void QQmlVmeProfiler::updateTypeName(const QString &typename)
+ * Updates the current profiler's type information. \a typeName is the type of
+ * object being created.
*/
-void QQmlVmeProfiler::updateTypeName(const QString &typeName)
-{
- if (QQmlProfilerService::enabled && running) {
- currentRange.typeName = typeName;
- QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName);
- }
-}
/*!
- * \brief QQmlVmeProfiler::pop Pops a paused profiler from the stack and restarts it
+ * \fn bool QQmlVmeProfiler::pop()
* Stops the currently running profiler, if any, then retrieves an old one from the stack
- * of paused profilers and starts that.
+ * of paused profilers and starts that if possible.
+ * Returns whether there actually is a running profiler after that.
*/
-void QQmlVmeProfiler::pop()
-{
- if (QQmlProfilerService::enabled && ranges.count() > 0) {
- start();
- currentRange = ranges.pop();
- QQmlProfilerService::instance->rangeLocation(
- QQmlProfilerService::Creating, currentRange.url, currentRange.line, currentRange.column);
- QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, currentRange.typeName);
- }
-}
/*!
- * \brief QQmlVmeProfiler::push Pushes the currently running profiler on the stack.
+ * \fn void QQmlVmeProfiler::push()
* Pushes the currently running profiler on the stack of paused profilers. Note: The profiler
* isn't paused here. That's a separate step. If it's never paused, but pop()'ed later that
* won't do any harm, though.
*/
-void QQmlVmeProfiler::push()
-{
- if (QQmlProfilerService::enabled && running)
- ranges.push(currentRange);
-}
/*!
- * \brief QQmlVmeProfiler::clear Stop all running profilers and clear all data.
+ * \fn void QQmlVmeProfiler::clear()
* Stops the currently running (foreground and background) profilers and removes all saved
* data about paused profilers.
*/
-void QQmlVmeProfiler::clear()
-{
- stop();
- ranges.clear();
- if (QQmlProfilerService::enabled) {
- for (int i = 0; i < backgroundRanges.count(); ++i) {
- QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
- }
- }
- backgroundRanges.clear();
- running = false;
-}
/*!
- * \brief QQmlVmeProfiler::stop Stop profiler running in the foreground, if any.
+ * \fn void QQmlVmeProfiler::stop()
+ * Stop profiler running in the foreground, if any.
*/
-void QQmlVmeProfiler::stop()
-{
- if (QQmlProfilerService::enabled && running) {
- QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
- currentRange.clear();
- running = false;
- }
-}
+
/*!
- * \brief QQmlVmeProfiler::background Push the current profiler to the background.
- * Push the profiler currently running in the foreground to the background so that it
+ * \fn void QQmlVmeProfiler::background()
+ * Pushes the profiler currently running in the foreground to the background so that it
* won't be stopped by stop() or start(). There can be multiple profilers in the background.
* You can retrieve them in reverse order by calling foreground().
*/
-void QQmlVmeProfiler::background()
-{
- if (QQmlProfilerService::enabled && running) {
- backgroundRanges.push(currentRange);
- running = false;
- }
-}
/*!
- * \brief QQmlVmeProfiler::foreground Retrieve a profiler from the background
- * Stop the profiler currently running in the foreground, if any and put the next profiler
- * from the background in its place.
+ * \fn bool QQmlVmeProfiler::foreground()
+ * Stops the profiler currently running in the foreground, if any and puts the next profiler
+ * from the background in its place if there are any profiles in the background.
+ * Returns Whethere there actually is a valid running profiler afterwards.
*/
-bool QQmlVmeProfiler::foreground()
-{
- if (QQmlProfilerService::enabled && backgroundRanges.count() > 0) {
- stop();
- currentRange = backgroundRanges.pop();
- running = true;
- return true;
- }
- return false;
-}
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index 86807eacec..1261597f1e 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -294,7 +294,13 @@ public:
int line;
int column;
QString typeName;
- void clear();
+ void clear()
+ {
+ url.clear();
+ line = 0;
+ column = 0;
+ typeName.clear();
+ }
};
QQmlVmeProfiler() :
@@ -307,19 +313,98 @@ public:
clear();
}
- void clear();
+ void clear()
+ {
+ stop();
+ ranges.clear();
+ if (QQmlProfilerService::enabled) {
+ for (int i = 0; i < backgroundRanges.count(); ++i) {
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+ }
+ }
+ backgroundRanges.clear();
+ running = false;
+ }
- bool start();
- void stop();
+ bool start()
+ {
+ if (QQmlProfilerService::enabled) {
+ currentRange.clear();
+ if (running)
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+ else
+ running = true;
+ QQmlProfilerService::instance->startRange(QQmlProfilerService::Creating);
+ return true;
+ }
+ return false;
+ }
- void updateLocation(const QUrl &url, int line, int column);
- void updateTypeName(const QString &typeName);
+ void stop()
+ {
+ if (QQmlProfilerService::enabled && running) {
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+ currentRange.clear();
+ running = false;
+ }
+ }
- void pop();
- void push();
+ void updateLocation(const QUrl &url, int line, int column)
+ {
+ if (QQmlProfilerService::enabled && running) {
+ currentRange.url = url;
+ currentRange.line = line;
+ currentRange.column = column;
+ QQmlProfilerService::instance->rangeLocation(
+ QQmlProfilerService::Creating, url, line, column);
+ }
+ }
- void background();
- bool foreground();
+ void updateTypeName(const QString &typeName)
+ {
+ if (QQmlProfilerService::enabled && running) {
+ currentRange.typeName = typeName;
+ QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName);
+ }
+ }
+
+ bool pop()
+ {
+ if (QQmlProfilerService::enabled && ranges.count() > 0) {
+ start();
+ currentRange = ranges.pop();
+ QQmlProfilerService::instance->rangeLocation(
+ QQmlProfilerService::Creating, currentRange.url, currentRange.line, currentRange.column);
+ QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, currentRange.typeName);
+ return true;
+ }
+ return false;
+ }
+
+ void push()
+ {
+ if (QQmlProfilerService::enabled && running)
+ ranges.push(currentRange);
+ }
+
+ void background()
+ {
+ if (QQmlProfilerService::enabled && running) {
+ backgroundRanges.push(currentRange);
+ running = false;
+ }
+ }
+
+ bool foreground()
+ {
+ if (QQmlProfilerService::enabled && backgroundRanges.count() > 0) {
+ stop();
+ currentRange = backgroundRanges.pop();
+ running = true;
+ return true;
+ }
+ return false;
+ }
private:
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 6a0cf0cf6d..8e1ac38f4f 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -1049,7 +1049,7 @@ bool QJSValue::hasOwnProperty(const QString &name) const
return false;
ScopedString s(scope, engine->newIdentifier(name));
- return o->__getOwnProperty__(s);
+ return o->hasOwnProperty(s);
}
/*!
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 94983f51e5..a90cea96c2 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -14,6 +14,7 @@ SOURCES += \
$$PWD/qv4managed.cpp \
$$PWD/qv4internalclass.cpp \
$$PWD/qv4sparsearray.cpp \
+ $$PWD/qv4arraydata.cpp \
$$PWD/qv4arrayobject.cpp \
$$PWD/qv4argumentsobject.cpp \
$$PWD/qv4booleanobject.cpp \
@@ -58,6 +59,7 @@ HEADERS += \
$$PWD/qv4managed_p.h \
$$PWD/qv4internalclass_p.h \
$$PWD/qv4sparsearray_p.h \
+ $$PWD/qv4arraydata_p.h \
$$PWD/qv4arrayobject_p.h \
$$PWD/qv4argumentsobject_p.h \
$$PWD/qv4booleanobject_p.h \
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 629c255b48..5094bafa66 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -51,8 +51,7 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
, context(context)
, fullyCreated(false)
{
- type = Type_ArgumentsObject;
- flags &= ~SimpleArray;
+ setArrayType(ArrayData::Complex);
ExecutionEngine *v4 = context->engine;
Scope scope(v4);
@@ -66,14 +65,12 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
memberData[CallerPropertyIndex] = pd;
arrayReserve(context->callData->argc);
- for (int i = 0; i < context->callData->argc; ++i)
- arrayData[i].value = context->callData->args[i];
- arrayDataLen = context->callData->argc;
+ arrayData->put(0, context->callData->args, context->callData->argc);
+ arrayData->setLength(context->callData->argc);
fullyCreated = true;
} else {
Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
memberData[CalleePropertyIndex].value = context->function->asReturnedValue();
- isNonStrictArgumentsObject = true;
}
Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
@@ -95,18 +92,18 @@ void ArgumentsObject::fullyCreate()
uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
uint argCount = qMin(context->realArgumentCount, context->callData->argc);
arrayReserve(argCount);
- ensureArrayAttributes();
+ arrayData->ensureAttributes();
context->engine->requireArgumentsAccessors(numAccessors);
for (uint i = 0; i < (uint)numAccessors; ++i) {
mappedArguments.append(context->callData->args[i]);
- arrayData[i] = context->engine->argumentsAccessors.at(i);
- arrayAttributes[i] = Attr_Accessor;
+ arrayData->data[i] = context->engine->argumentsAccessors.at(i);
+ arrayData->setAttributes(i, Attr_Accessor);
}
- for (uint i = numAccessors; i < argCount; ++i) {
- arrayData[i] = Property::fromValue(context->callData->args[i]);
- arrayAttributes[i] = Attr_Data;
- }
- arrayDataLen = argCount;
+ arrayData->setLength(numAccessors);
+ arrayData->put(numAccessors, context->callData->args + numAccessors, argCount - numAccessors);
+ for (uint i = numAccessors; i < argCount; ++i)
+ arrayData->setAttributes(i, Attr_Data);
+ arrayData->setLength(argCount);
fullyCreated = true;
}
@@ -116,27 +113,24 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
fullyCreate();
Scope scope(ctx);
- uint pidx = propertyIndexFromArrayIndex(index);
- Property *pd = arrayData + pidx;
+ Property *pd = arrayData->getProperty(index);
Property map;
PropertyAttributes mapAttrs;
bool isMapped = false;
if (pd && index < (uint)mappedArguments.size())
- isMapped = arrayAttributes && arrayAttributes[pidx].isAccessor() && pd->getter() == context->engine->argumentsAccessors.at(index).getter();
+ isMapped = arrayData->attributes(index).isAccessor() && pd->getter() == context->engine->argumentsAccessors.at(index).getter();
if (isMapped) {
map = *pd;
- mapAttrs = arrayAttributes[pidx];
- arrayAttributes[pidx] = Attr_Data;
+ mapAttrs = arrayData->attributes(index);
+ arrayData->setAttributes(index, Attr_Data);
pd->value = mappedArguments.at(index);
}
- isNonStrictArgumentsObject = false;
bool strict = ctx->strictMode;
ctx->strictMode = false;
- bool result = Object::__defineOwnProperty__(ctx, index, desc, attrs);
+ bool result = Object::defineOwnProperty2(ctx, index, desc, attrs);
ctx->strictMode = strict;
- isNonStrictArgumentsObject = true;
if (isMapped && attrs.isData()) {
ScopedCallData callData(scope, 1);
@@ -146,7 +140,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
if (attrs.isWritable()) {
*pd = map;
- arrayAttributes[pidx] = mapAttrs;
+ arrayData->setAttributes(index, mapAttrs);
}
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index d306fae92b..42b749cbb5 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -77,12 +77,17 @@ struct ArgumentsSetterFunction: FunctionObject
struct ArgumentsObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(ArgumentsObject)
CallContext *context;
bool fullyCreated;
QVector<SafeValue> mappedArguments;
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
+ static bool isNonStrictArgumentsObject(Managed *m) {
+ return m->internalClass->vtable->type == Type_ArgumentsObject &&
+ !static_cast<ArgumentsObject *>(m)->context->strictMode;
+ }
enum {
LengthPropertyIndex = 0,
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
new file mode 100644
index 0000000000..0ec36bd9db
--- /dev/null
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -0,0 +1,563 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module 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 "qv4arraydata_p.h"
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+using namespace QV4;
+
+const ArrayVTable ArrayData::static_vtbl =
+{
+ ArrayData::Simple,
+ ArrayData::freeData,
+ ArrayData::reserve,
+ ArrayData::get,
+ ArrayData::put,
+ ArrayData::putArray,
+ ArrayData::del,
+ ArrayData::setAttribute,
+ ArrayData::attribute,
+ ArrayData::push_front,
+ ArrayData::pop_front,
+ ArrayData::truncate
+};
+
+const ArrayVTable SparseArrayData::static_vtbl =
+{
+ ArrayData::Sparse,
+ SparseArrayData::freeData,
+ SparseArrayData::reserve,
+ SparseArrayData::get,
+ SparseArrayData::put,
+ SparseArrayData::putArray,
+ SparseArrayData::del,
+ SparseArrayData::setAttribute,
+ SparseArrayData::attribute,
+ SparseArrayData::push_front,
+ SparseArrayData::pop_front,
+ SparseArrayData::truncate
+};
+
+
+void ArrayData::getHeadRoom(ArrayData *d)
+{
+ Q_ASSERT(d);
+ Q_ASSERT(!d->offset);
+ d->offset = qMax(d->len >> 2, (uint)16);
+ Property *newArray = new Property[d->offset + d->alloc];
+ memcpy(newArray + d->offset, d->data, d->len*sizeof(Property));
+ delete [] d->data;
+ d->data = newArray + d->offset;
+ if (d->attrs) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[d->offset + d->alloc];
+ memcpy(newAttrs + d->offset, d->attrs, d->len*sizeof(PropertyAttributes));
+ delete [] d->attrs;
+ d->attrs = newAttrs + d->offset;
+ }
+}
+
+void ArrayData::reserve(ArrayData *d, uint n)
+{
+ if (n < 8)
+ n = 8;
+ if (n <= d->alloc)
+ return;
+
+ d->alloc = qMax(n, 2*d->alloc);
+ Property *newArrayData = new Property[d->alloc + d->offset];
+ if (d->data) {
+ memcpy(newArrayData + d->offset, d->data, sizeof(Property)*d->len);
+ delete [] (d->data - d->offset);
+ }
+ d->data = newArrayData + d->offset;
+
+ if (d->attrs) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[d->alloc];
+ memcpy(newAttrs, d->attrs, sizeof(PropertyAttributes)*d->len);
+ delete [] (d->attrs - d->offset);
+
+ d->attrs = newAttrs;
+ }
+}
+
+void ArrayData::ensureAttributes()
+{
+ if (attrs)
+ return;
+
+ if (type == Simple)
+ type = Complex;
+ attrs = new PropertyAttributes[alloc + offset];
+ attrs += offset;
+ for (uint i = 0; i < len; ++i)
+ attrs[i] = Attr_Data;
+}
+
+
+void ArrayData::freeData(ArrayData *d)
+{
+ delete [] (d->data - d->offset);
+ if (d->attrs)
+ delete [] (d->attrs - d->offset);
+ delete d;
+}
+
+ReturnedValue ArrayData::get(const ArrayData *d, uint index)
+{
+ if (index >= d->len)
+ return Primitive::emptyValue().asReturnedValue();
+ return d->data[index].value.asReturnedValue();
+}
+
+bool ArrayData::put(ArrayData *d, uint index, ValueRef value)
+{
+ Q_ASSERT(!d->attrs || !d->attrs->isAccessor());
+ // ### honour attributes
+ d->data[index].value = value;
+ return true;
+}
+
+bool ArrayData::del(ArrayData *d, uint index)
+{
+ if (index >= d->len)
+ return true;
+
+ if (!d->attrs || d->attrs[index].isConfigurable()) {
+ d->data[index].value = Primitive::emptyValue();
+ if (d->attrs)
+ d->attrs[index] = Attr_Data;
+ return true;
+ }
+ if (d->data[index].value.isEmpty())
+ return true;
+ return false;
+}
+
+void ArrayData::setAttribute(ArrayData *d, uint index, PropertyAttributes attrs)
+{
+ d->attrs[index] = attrs;
+}
+
+PropertyAttributes ArrayData::attribute(const ArrayData *d, uint index)
+{
+ return d->attrs[index];
+}
+
+void ArrayData::push_front(ArrayData *d, SafeValue *values, uint n)
+{
+ Q_ASSERT(!d->attrs);
+ for (int i = n - 1; i >= 0; --i) {
+ if (!d->offset)
+ ArrayData::getHeadRoom(d);
+
+ --d->offset;
+ --d->data;
+ ++d->len;
+ ++d->alloc;
+ d->data->value = values[i].asReturnedValue();
+ }
+
+}
+
+ReturnedValue ArrayData::pop_front(ArrayData *d)
+{
+ Q_ASSERT(!d->attrs);
+ if (!d->len)
+ return Encode::undefined();
+
+ ReturnedValue v = d->data[0].value.isEmpty() ? Encode::undefined() : d->data[0].value.asReturnedValue();
+ ++d->offset;
+ ++d->data;
+ --d->len;
+ --d->alloc;
+ return v;
+}
+
+uint ArrayData::truncate(ArrayData *d, uint newLen)
+{
+ if (d->attrs) {
+ Property *it = d->data + d->len;
+ const Property *begin = d->data + newLen;
+ while (--it >= begin) {
+ if (!it->value.isEmpty() && !d->attrs[it - d->data].isConfigurable()) {
+ newLen = it - d->data + 1;
+ break;
+ }
+ it->value = Primitive::emptyValue();
+ }
+ }
+ d->len = newLen;
+ return newLen;
+}
+
+bool ArrayData::putArray(ArrayData *d, uint index, SafeValue *values, uint n)
+{
+ if (index + n > d->alloc)
+ reserve(d, index + n + 1);
+ for (uint i = d->len; i < index; ++i)
+ d->data[i].value = Primitive::emptyValue();
+ for (uint i = 0; i < n; ++i)
+ d->data[index + i].value = values[i];
+ d->len = qMax(d->len, index + n);
+ return true;
+}
+
+void SparseArrayData::free(ArrayData *d, uint idx)
+{
+ Q_ASSERT(d && d->type == ArrayData::Sparse);
+ SparseArrayData *dd = static_cast<SparseArrayData *>(d);
+ Property &pd = dd->data[idx];
+ pd.value.uint_32 = dd->freeList;
+ dd->freeList = idx;
+ if (dd->attrs)
+ dd->attrs[idx].clear();
+}
+
+
+void SparseArrayData::freeData(ArrayData *d)
+{
+ delete static_cast<SparseArrayData *>(d)->sparse;
+ ArrayData::freeData(d);
+}
+
+void SparseArrayData::reserve(ArrayData *d, uint n)
+{
+ if (n < 8)
+ n = 8;
+ if (n <= d->alloc)
+ return;
+
+ SparseArrayData *dd = static_cast<SparseArrayData *>(d);
+ // ### FIXME
+ dd->len = dd->alloc;
+ dd->alloc = qMax(n, 2*dd->alloc);
+ Property *newArrayData = new Property[dd->alloc];
+ if (dd->data) {
+ memcpy(newArrayData, dd->data, sizeof(Property)*dd->len);
+ delete [] dd->data;
+ }
+ dd->data = newArrayData;
+ if (dd->attrs) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[dd->alloc];
+ memcpy(newAttrs, dd->attrs, sizeof(PropertyAttributes)*dd->len);
+ delete [] dd->attrs;
+ dd->attrs = newAttrs;
+ }
+ for (uint i = dd->freeList; i < dd->alloc; ++i)
+ dd->data[i].value = Primitive::fromInt32(i + 1);
+}
+
+uint SparseArrayData::allocate(ArrayData *d)
+{
+ Q_ASSERT(d->type == ArrayData::Sparse);
+ SparseArrayData *dd = static_cast<SparseArrayData *>(d);
+ uint idx = dd->freeList;
+ if (dd->alloc == dd->freeList)
+ reserve(d, d->alloc + 1);
+ dd->freeList = dd->data[dd->freeList].value.uint_32;
+ if (dd->attrs)
+ dd->attrs[idx].setType(PropertyAttributes::Data);
+ return idx;
+}
+
+ReturnedValue SparseArrayData::get(const ArrayData *d, uint index)
+{
+ SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse->findNode(index);
+ if (!n)
+ return Primitive::emptyValue().asReturnedValue();
+ return d->data[n->value].value.asReturnedValue();
+}
+
+bool SparseArrayData::put(ArrayData *d, uint index, ValueRef value)
+{
+ // ### honour attributes
+ SparseArrayNode *n = static_cast<SparseArrayData *>(d)->sparse->insert(index);
+ if (n->value == UINT_MAX)
+ n->value = allocate(d);
+ d->data[n->value].value = value;
+ return true;
+}
+
+bool SparseArrayData::del(ArrayData *d, uint index)
+{
+ SparseArrayData *dd = static_cast<SparseArrayData *>(d);
+ SparseArrayNode *n = dd->sparse->findNode(index);
+ if (!n)
+ return true;
+
+ uint pidx = n->value;
+ Q_ASSERT(!dd->data[pidx].value.isEmpty());
+
+ if (!dd->attrs || dd->attrs[pidx].isConfigurable()) {
+ d->data[pidx].value.int_32 = static_cast<SparseArrayData *>(d)->freeList;
+ static_cast<SparseArrayData *>(d)->freeList = pidx;
+ static_cast<SparseArrayData *>(d)->sparse->erase(n);
+ return true;
+ }
+ return false;
+}
+
+void SparseArrayData::setAttribute(ArrayData *d, uint index, PropertyAttributes attrs)
+{
+ SparseArrayNode *n = static_cast<SparseArrayData *>(d)->sparse->insert(index);
+ if (n->value == UINT_MAX)
+ n->value = allocate(d);
+ d->attrs[n->value] = attrs;
+}
+
+PropertyAttributes SparseArrayData::attribute(const ArrayData *d, uint index)
+{
+ SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse->insert(index);
+ if (!n)
+ return PropertyAttributes();
+ return d->attrs[n->value];
+}
+
+void SparseArrayData::push_front(ArrayData *d, SafeValue *values, uint n)
+{
+ Q_ASSERT(!d->attrs);
+ for (int i = n - 1; i >= 0; --i) {
+ uint idx = allocate(d);
+ d->data[idx].value = values[i];
+ static_cast<SparseArrayData *>(d)->sparse->push_front(idx);
+ }
+}
+
+ReturnedValue SparseArrayData::pop_front(ArrayData *d)
+{
+ Q_ASSERT(!d->attrs);
+ uint idx = static_cast<SparseArrayData *>(d)->sparse->pop_front();
+ ReturnedValue v;
+ if (idx != UINT_MAX) {
+ v = d->data[idx].value.asReturnedValue();
+ SparseArrayData::free(d, idx);
+ } else {
+ v = Encode::undefined();
+ }
+ return v;
+}
+
+uint SparseArrayData::truncate(ArrayData *d, uint newLen)
+{
+ SparseArrayNode *begin = static_cast<SparseArrayData *>(d)->sparse->lowerBound(newLen);
+ if (begin != static_cast<SparseArrayData *>(d)->sparse->end()) {
+ SparseArrayNode *it = static_cast<SparseArrayData *>(d)->sparse->end()->previousNode();
+ while (1) {
+ Property &pd = d->data[it->value];
+ if (d->attrs) {
+ if (!d->attrs[it->value].isConfigurable()) {
+ newLen = it->key() + 1;
+ break;
+ }
+ }
+ pd.value.tag = Value::Empty_Type;
+ pd.value.int_32 = static_cast<SparseArrayData *>(d)->freeList;
+ static_cast<SparseArrayData *>(d)->freeList = it->value;
+ bool brk = (it == begin);
+ SparseArrayNode *prev = it->previousNode();
+ static_cast<SparseArrayData *>(d)->sparse->erase(it);
+ if (brk)
+ break;
+ it = prev;
+ }
+ }
+ return newLen;
+}
+
+bool SparseArrayData::putArray(ArrayData *d, uint index, SafeValue *values, uint n)
+{
+ for (uint i = 0; i < n; ++i)
+ put(d, index + i, values[i]);
+ d->len = qMax(d->len, index + n);
+ return true;
+}
+
+
+uint ArrayData::append(Object *o, const ArrayObject *otherObj, uint n)
+{
+ ArrayData *d = o->arrayData;
+ if (!n)
+ return d->len;
+
+ const ArrayData *other = otherObj->arrayData;
+
+ if (other->isSparse()) {
+ o->initSparseArray();
+ d = o->arrayData;
+ }
+
+ uint oldSize = d->len;
+
+ // ### copy attributes as well!
+ if (d->type == ArrayData::Sparse) {
+ if (other->isSparse()) {
+ for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
+ it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode())
+ // ### accessor properties
+ o->arraySet(d->len + it->key(), other->data[it->value].value);
+ } else {
+ d->vtable->reserve(d, oldSize + n);
+ memcpy(d->data + oldSize, other->data, n*sizeof(Property));
+ if (d->attrs)
+ std::fill(d->attrs + oldSize, d->attrs + oldSize + n, PropertyAttributes(Attr_Data));
+ for (uint i = 0; i < n; ++i) {
+ SparseArrayNode *n = static_cast<SparseArrayData *>(d)->sparse->insert(d->len + i);
+ n->value = oldSize + i;
+ }
+ }
+ } else if (other->length()) {
+ d->vtable->reserve(d, oldSize + other->length());
+ if (oldSize > d->len) {
+ for (uint i = d->len; i < oldSize; ++i)
+ d->data[i].value = Primitive::emptyValue();
+ }
+ if (other->attrs) {
+ for (uint i = 0; i < other->len; ++i) {
+ bool exists;
+ d->data[oldSize + i].value = const_cast<ArrayObject *>(otherObj)->getIndexed(i, &exists);
+ d->len = oldSize + i + 1;
+ o->arrayData->setAttributes(oldSize + i, Attr_Data);
+ if (!exists)
+ d->data[oldSize + i].value = Primitive::emptyValue();
+ }
+ } else {
+ d->len = oldSize + other->len;
+ memcpy(d->data + oldSize, other->data, other->len*sizeof(Property));
+ if (d->attrs)
+ std::fill(d->attrs + oldSize, d->attrs + oldSize + other->len, PropertyAttributes(Attr_Data));
+ }
+ }
+
+ return oldSize + n;
+}
+
+Property *ArrayData::insert(Object *o, uint index)
+{
+ Property *pd;
+ if (o->arrayData->type != ArrayData::Sparse && (index < 0x1000 || index < o->arrayData->len + (o->arrayData->len >> 2))) {
+ if (index >= o->arrayData->alloc)
+ o->arrayReserve(index + 1);
+ if (index >= o->arrayData->len) {
+ // mark possible hole in the array
+ for (uint i = o->arrayData->len; i < index; ++i)
+ o->arrayData->data[i].value = Primitive::emptyValue();
+ o->arrayData->len = index + 1;
+ }
+ pd = o->arrayData->data + index;
+ } else {
+ o->initSparseArray();
+ SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index);
+ if (n->value == UINT_MAX)
+ n->value = SparseArrayData::allocate(o->arrayData);
+ pd = o->arrayData->data + n->value;
+ }
+ return pd;
+}
+
+void ArrayData::markObjects(ExecutionEngine *e)
+{
+ if (type == ArrayData::Simple) {
+ for (uint i = 0; i < len; ++i)
+ data[i].value.mark(e);
+ return;
+ } else {
+ for (uint i = 0; i < len; ++i) {
+ const Property &pd = data[i];
+ if (attrs && attrs[i].isAccessor()) {
+ if (pd.getter())
+ pd.getter()->mark(e);
+ if (pd.setter())
+ pd.setter()->mark(e);
+ } else {
+ pd.value.mark(e);
+ }
+ }
+ }
+
+}
+
+void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint len)
+{
+ ArrayData *d = thisObject->arrayData;
+ if (!d || !d->len)
+ return;
+
+ if (d->type == ArrayData::Sparse) {
+ context->throwUnimplemented(QStringLiteral("Object::sort unimplemented for sparse arrays"));
+ return;
+ }
+
+ if (len > d->len)
+ len = d->len;
+
+ // The spec says the sorting goes through a series of get,put and delete operations.
+ // this implies that the attributes don't get sorted around.
+ // behavior of accessor properties is implementation defined. We simply turn them all
+ // into data properties and then sort. This is in line with the sentence above.
+ if (d->attrs) {
+ for (uint i = 0; i < len; i++) {
+ if (d->data[i].value.isEmpty()) {
+ while (--len > i)
+ if (!d->data[len].value.isEmpty())
+ break;
+ d->data[i].value = thisObject->getValue(d->data + len, d->attrs ? d->attrs[len] : Attr_Data);
+ if (d->attrs)
+ d->attrs[i] = Attr_Data;
+ d->data[len].value = Primitive::emptyValue();
+ } else if (d->attrs && d->attrs[i].isAccessor()) {
+ d->data[i].value = thisObject->getValue(d->data + i, d->attrs[i]);
+ d->attrs[i] = Attr_Data;
+ }
+ }
+ }
+
+ if (!(comparefn->isUndefined() || comparefn->asObject())) {
+ context->throwTypeError();
+ return;
+ }
+
+ ArrayElementLessThan lessThan(context, thisObject, comparefn);
+
+ if (!len)
+ return;
+ Property *begin = d->data;
+ std::sort(begin, begin + len, lessThan);
+}
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
new file mode 100644
index 0000000000..98968fada2
--- /dev/null
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module 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 QV4ARRAYDATA_H
+#define QV4ARRAYDATA_H
+
+#include "qv4global_p.h"
+#include "qv4managed_p.h"
+#include "qv4property_p.h"
+#include "qv4sparsearray_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ArrayData;
+
+struct ArrayVTable
+{
+ uint type;
+ void (*freeData)(ArrayData *d);
+ void (*reserve)(ArrayData *d, uint n);
+ ReturnedValue (*get)(const ArrayData *d, uint index);
+ bool (*put)(ArrayData *d, uint index, ValueRef value);
+ bool (*putArray)(ArrayData *d, uint index, SafeValue *values, uint n);
+ bool (*del)(ArrayData *d, uint index);
+ void (*setAttribute)(ArrayData *d, uint index, PropertyAttributes attrs);
+ PropertyAttributes (*attribute)(const ArrayData *d, uint index);
+ void (*push_front)(ArrayData *d, SafeValue *values, uint n);
+ ReturnedValue (*pop_front)(ArrayData *d);
+ uint (*truncate)(ArrayData *d, uint newLen);
+};
+
+
+struct Q_QML_EXPORT ArrayData
+{
+ ArrayData()
+ : vtable(&static_vtbl)
+ , offset(0)
+ , len(0)
+ , alloc(0)
+ , type(0)
+ , attrs(0)
+ , data(0)
+ {
+ }
+
+ enum Type {
+ Simple = 0,
+ Complex = 1,
+ Sparse = 2,
+ Custom = 3
+ };
+
+ const ArrayVTable *vtable;
+ uint offset;
+ uint len;
+ uint alloc;
+ uint type;
+ PropertyAttributes *attrs;
+ Property *data;
+
+ bool isSparse() const { return this && type == Sparse; }
+
+ uint length() const {
+ return this ? len : 0;
+ }
+ void setLength(uint l) {
+ Q_ASSERT(this);
+ len = l;
+ }
+
+ bool hasAttributes() const {
+ return this && attrs;
+ }
+ void ensureAttributes();
+ PropertyAttributes attributes(int i) const {
+ Q_ASSERT(this);
+ return attrs ? vtable->attribute(this, i) : Attr_Data;
+ }
+ void setAttributes(uint i, PropertyAttributes a) {
+ Q_ASSERT(this);
+ if (attrs || a != Attr_Data) {
+ ensureAttributes();
+ a.resolve();
+ vtable->setAttribute(this, i, a);
+ }
+ }
+
+ bool isEmpty(uint i) const {
+ if (!this)
+ return true;
+ return (vtable->get(this, i) == Primitive::emptyValue().asReturnedValue());
+ }
+
+
+ inline void free() {
+ vtable->freeData(this);
+ }
+
+ inline void push_front(SafeValue *values, uint nValues) {
+ vtable->push_front(this, values, nValues);
+ }
+ inline ReturnedValue pop_front() {
+ return vtable->pop_front(this);
+ }
+ inline uint push_back(uint l, uint n, SafeValue *values) {
+ vtable->putArray(this, l, values, n);
+ return len;
+ }
+ inline bool deleteIndex(uint index) {
+ return vtable->del(this, index);
+ }
+ inline uint truncate(uint newLen) {
+ if (!this || len < newLen)
+ return newLen;
+ return vtable->truncate(this, newLen);
+ }
+ bool put(uint index, ValueRef value) {
+ return vtable->put(this, index, value);
+ }
+ bool put(uint index, SafeValue *values, uint n) {
+ return vtable->putArray(this, index, values, n);
+ }
+ ReturnedValue get(uint i) const {
+ if (!this)
+ return Primitive::emptyValue().asReturnedValue();
+ return vtable->get(this, i);
+ }
+ inline Property *getProperty(uint index) const;
+
+
+
+ static void sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint dataLen);
+ static uint append(Object *o, const ArrayObject *otherObj, uint n);
+ static Property *insert(Object *o, uint index);
+ void markObjects(ExecutionEngine *e);
+
+ static void getHeadRoom(ArrayData *d);
+ static void reserve(ArrayData *d, uint n);
+
+ static void freeData(ArrayData *d);
+ static ReturnedValue get(const ArrayData *d, uint index);
+ static bool put(ArrayData *d, uint index, ValueRef value);
+ static bool putArray(ArrayData *d, uint index, SafeValue *values, uint n);
+ static bool del(ArrayData *d, uint index);
+ static void setAttribute(ArrayData *d, uint index, PropertyAttributes attrs);
+ static PropertyAttributes attribute(const ArrayData *d, uint index);
+ static void push_front(ArrayData *d, SafeValue *values, uint n);
+ static ReturnedValue pop_front(ArrayData *d);
+ static uint truncate(ArrayData *d, uint newLen);
+
+ static const ArrayVTable static_vtbl;
+};
+
+struct Q_QML_EXPORT SparseArrayData : public ArrayData
+{
+ SparseArrayData()
+ : freeList(0)
+ , sparse(0)
+ { vtable = &static_vtbl; }
+
+ uint freeList;
+ SparseArray *sparse;
+
+ static uint allocate(ArrayData *d);
+ static void free(ArrayData *d, uint idx);
+
+ static void freeData(ArrayData *d);
+ static void reserve(ArrayData *d, uint n);
+ static ReturnedValue get(const ArrayData *d, uint index);
+ static bool put(ArrayData *d, uint index, ValueRef value);
+ static bool putArray(ArrayData *d, uint index, SafeValue *values, uint n);
+ static bool del(ArrayData *d, uint index);
+ static void setAttribute(ArrayData *d, uint index, PropertyAttributes attrs);
+ static PropertyAttributes attribute(const ArrayData *d, uint index);
+ static void push_front(ArrayData *d, SafeValue *values, uint n);
+ static ReturnedValue pop_front(ArrayData *d);
+ static uint truncate(ArrayData *d, uint newLen);
+
+ static const ArrayVTable static_vtbl;
+};
+
+
+inline Property *ArrayData::getProperty(uint index) const
+{
+ if (!this)
+ return 0;
+ if (type != Sparse) {
+ if (index >= len || data[index].value.isEmpty())
+ return 0;
+ return data + index;
+ } else {
+ SparseArrayNode *n = static_cast<const SparseArrayData *>(this)->sparse->findNode(index);
+ if (!n)
+ return 0;
+ return data + n->value;
+ }
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 296471692c..eb8a5301de 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -72,9 +72,8 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
} else {
len = callData->argc;
a->arrayReserve(len);
- for (unsigned int i = 0; i < len; ++i)
- a->arrayData[i].value = callData->args[i];
- a->arrayDataLen = len;
+ a->arrayData->put(0, callData->args, len);
+ a->arrayData->setLength(len);
}
a->setArrayLengthUnchecked(len);
@@ -122,15 +121,6 @@ void ArrayPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1);
}
-uint ArrayPrototype::getLength(ExecutionContext *ctx, ObjectRef o)
-{
- if (o->isArrayObject())
- return o->arrayLength();
- Scope scope(ctx);
- ScopedValue v(scope, o->get(ctx->engine->id_length));
- return v->toUInt32();
-}
-
ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx)
{
bool isArray = ctx->callData->argc && ctx->callData->args[0].asArrayObject();
@@ -180,15 +170,17 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
eltAsObj = ctx->callData->args[i];
elt = ctx->callData->args[i];
if (elt) {
- result->arrayConcat(elt.getPointer());
+ uint n = elt->getLength();
+ uint newLen = ArrayData::append(result.getPointer(), elt.getPointer(), n);
+ result->setArrayLengthUnchecked(newLen);
} else if (eltAsObj && eltAsObj->isListType()) {
- const uint startIndex = getLength(ctx, result);
- for (int i = 0, len = getLength(ctx, eltAsObj); i < len; ++i) {
+ const uint startIndex = result->getLength();
+ for (int i = 0, len = eltAsObj->getLength(); i < len; ++i) {
entry = eltAsObj->getIndexed(i);
result->putIndexed(startIndex + i, entry);
}
} else {
- result->arraySet(getLength(ctx, result), ctx->callData->args[i]);
+ result->arraySet(result->getLength(), ctx->callData->args[i]);
}
}
@@ -218,7 +210,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
// ### FIXME
if (ArrayObject *a = self->asArrayObject()) {
ScopedValue e(scope);
- for (uint i = 0; i < a->arrayLength(); ++i) {
+ for (uint i = 0; i < a->getLength(); ++i) {
if (i)
R += r4;
@@ -260,7 +252,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
if (!len) {
if (!instance->isArrayObject())
@@ -288,7 +280,10 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+
+ instance->arrayCreate();
+
+ uint len = instance->getLength();
if (len + ctx->callData->argc < len) {
// ughh...
@@ -308,21 +303,8 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
return Encode(newLen);
}
- if (!instance->protoHasArray() && instance->arrayDataLen <= len) {
- for (int i = 0; i < ctx->callData->argc; ++i) {
- if (!instance->sparseArray) {
- if (len >= instance->arrayAlloc)
- instance->arrayReserve(len + 1);
- instance->arrayData[len].value = ctx->callData->args[i];
- if (instance->arrayAttributes)
- instance->arrayAttributes[len] = Attr_Data;
- instance->arrayDataLen = len + 1;
- } else {
- uint j = instance->allocArrayValue(ctx->callData->args[i]);
- instance->sparseArray->push_back(j, len);
- }
- ++len;
- }
+ if (!instance->protoHasArray() && instance->arrayData->length() <= len) {
+ len = instance->arrayData->push_back(len, ctx->callData->argc, ctx->callData->args);
} else {
for (int i = 0; i < ctx->callData->argc; ++i)
instance->putIndexed(len + i, ctx->callData->args[i]);
@@ -342,7 +324,7 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint length = getLength(ctx, instance);
+ uint length = instance->getLength();
int lo = 0, hi = length - 1;
@@ -374,7 +356,10 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+
+ instance->arrayCreate();
+
+ uint len = instance->getLength();
if (!len) {
if (!instance->isArrayObject())
@@ -382,28 +367,14 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
return Encode::undefined();
}
- Property *front = 0;
- uint pidx = instance->propertyIndexFromArrayIndex(0);
- if (pidx < UINT_MAX && !instance->arrayData[pidx].value.isEmpty())
- front = instance->arrayData + pidx;
+ ScopedValue result(scope);
- ScopedValue result(scope, front ? instance->getValue(front, instance->arrayAttributes ? instance->arrayAttributes[pidx] : Attr_Data) : Encode::undefined());
-
- if (!instance->protoHasArray() && instance->arrayDataLen <= len) {
- if (!instance->sparseArray) {
- if (instance->arrayDataLen) {
- ++instance->arrayOffset;
- ++instance->arrayData;
- --instance->arrayDataLen;
- --instance->arrayAlloc;
- if (instance->arrayAttributes)
- ++instance->arrayAttributes;
- }
- } else {
- uint idx = instance->sparseArray->pop_front();
- instance->freeArrayValue(idx);
- }
+ if (!instance->protoHasArray() && !instance->arrayData->hasAttributes() && instance->arrayData->length() <= len) {
+ result = instance->arrayData->pop_front();
} else {
+ result = instance->getIndexed(0);
+ if (scope.hasException())
+ return Encode::undefined();
ScopedValue v(scope);
// do it the slow way
for (uint k = 1; k < len; ++k) {
@@ -415,6 +386,8 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
instance->putIndexed(k - 1, v);
else
instance->deleteIndexedProperty(k - 1);
+ if (scope.hasException())
+ return Encode::undefined();
}
instance->deleteIndexedProperty(len - 1);
if (scope.hasException())
@@ -436,7 +409,7 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
return Encode::undefined();
Scoped<ArrayObject> result(scope, ctx->engine->newArrayObject());
- uint len = getLength(ctx, o);
+ uint len = o->getLength();
double s = ScopedValue(scope, ctx->argument(0))->toInteger();
uint start;
if (s < 0)
@@ -477,10 +450,10 @@ ReturnedValue ArrayPrototype::method_sort(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
ScopedValue comparefn(scope, ctx->argument(0));
- instance->arraySort(ctx, instance, comparefn, len);
+ ArrayData::sort(ctx, instance, comparefn, len);
return ctx->callData->thisObject.asReturnedValue();
}
@@ -490,7 +463,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<ArrayObject> newArray(scope, ctx->engine->newArrayObject());
@@ -504,17 +477,21 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, ctx->argument(1))->toInteger(), 0.), (double)(len - start));
newArray->arrayReserve(deleteCount);
+ ScopedValue v(scope);
for (uint i = 0; i < deleteCount; ++i) {
- newArray->arrayData[i].value = instance->getIndexed(start + i);
+ bool exists;
+ v = instance->getIndexed(start + i, &exists);
if (scope.hasException())
return Encode::undefined();
- newArray->arrayDataLen = i + 1;
+ if (exists) {
+ newArray->arrayData->put(i, v);
+ newArray->arrayData->setLength(i + 1);
+ }
}
newArray->setArrayLengthUnchecked(deleteCount);
uint itemCount = ctx->callData->argc < 2 ? 0 : ctx->callData->argc - 2;
- ScopedValue v(scope);
if (itemCount < deleteCount) {
for (uint k = start; k < len - deleteCount; ++k) {
bool exists;
@@ -568,32 +545,15 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
- ScopedValue v(scope);
- if (!instance->protoHasArray() && instance->arrayDataLen <= len) {
- for (int i = ctx->callData->argc - 1; i >= 0; --i) {
- v = ctx->argument(i);
-
- if (!instance->sparseArray) {
- if (!instance->arrayOffset)
- instance->getArrayHeadRoom();
-
- --instance->arrayOffset;
- --instance->arrayData;
- ++instance->arrayDataLen;
- ++instance->arrayAlloc;
- if (instance->arrayAttributes) {
- --instance->arrayAttributes;
- *instance->arrayAttributes = Attr_Data;
- }
- instance->arrayData->value = v.asReturnedValue();
- } else {
- uint idx = instance->allocArrayValue(v);
- instance->sparseArray->push_front(idx);
- }
- }
+ instance->arrayCreate();
+
+ uint len = instance->getLength();
+
+ if (!instance->protoHasArray() && !instance->arrayData->hasAttributes() && instance->arrayData->length() <= len) {
+ instance->arrayData->push_front(ctx->callData->args, ctx->callData->argc);
} else {
+ ScopedValue v(scope);
for (uint k = len; k > 0; --k) {
bool exists;
v = instance->getIndexed(k - 1, &exists);
@@ -622,7 +582,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
if (!len)
return Encode(-1);
@@ -651,7 +611,48 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
return Encode(-1);
}
- return instance->arrayIndexOf(searchValue, fromIndex, len, ctx, instance.getPointer());
+ ScopedValue value(scope);
+
+ if ((instance->arrayData && instance->arrayType() != ArrayData::Simple) || instance->protoHasArray()) {
+ // lets be safe and slow
+ for (uint i = fromIndex; i < len; ++i) {
+ bool exists;
+ value = instance->getIndexed(i, &exists);
+ if (scope.hasException())
+ return Encode::undefined();
+ if (exists && __qmljs_strict_equal(value, searchValue))
+ return Encode(i);
+ }
+ } else if (!instance->arrayData) {
+ return Encode(-1);
+ } else if (instance->arrayType() == ArrayData::Sparse) {
+ for (SparseArrayNode *n = static_cast<SparseArrayData *>(instance->arrayData)->sparse->lowerBound(fromIndex);
+ n != static_cast<SparseArrayData *>(instance->arrayData)->sparse->end() && n->key() < len; n = n->nextNode()) {
+ value = instance->getValue(instance->arrayData->data + n->value,
+ instance->arrayData->attrs ? instance->arrayData->attrs[n->value] : Attr_Data);
+ if (scope.hasException())
+ return Encode::undefined();
+ if (__qmljs_strict_equal(value, searchValue))
+ return Encode(n->key());
+ }
+ } else {
+ if (len > instance->arrayData->length())
+ len = instance->arrayData->length();
+ Property *pd = instance->arrayData->data;
+ Property *end = pd + len;
+ pd += fromIndex;
+ while (pd < end) {
+ if (!pd->value.isEmpty()) {
+ value = instance->getValue(pd, instance->arrayData->attributes(pd - instance->arrayData->data));
+ if (scope.hasException())
+ return Encode::undefined();
+ if (__qmljs_strict_equal(value, searchValue))
+ return Encode((uint)(pd - instance->arrayData->data));
+ }
+ ++pd;
+ }
+ }
+ return Encode(-1);
}
ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
@@ -661,7 +662,7 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
if (!len)
return Encode(-1);
@@ -707,7 +708,7 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
@@ -741,7 +742,7 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
@@ -775,7 +776,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
@@ -806,7 +807,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
@@ -843,7 +844,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
@@ -884,7 +885,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
@@ -934,7 +935,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
if (!instance)
return Encode::undefined();
- uint len = getLength(ctx, instance);
+ uint len = instance->getLength();
Scoped<FunctionObject> callback(scope, ctx->argument(0));
if (!callback)
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index 7e809f9064..641be86e2c 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -64,8 +64,6 @@ struct ArrayPrototype: ArrayObject
void init(ExecutionEngine *engine, ObjectRef ctor);
- static uint getLength(ExecutionContext *ctx, ObjectRef o);
-
static ReturnedValue method_isArray(CallContext *ctx);
static ReturnedValue method_toString(CallContext *ctx);
static ReturnedValue method_toLocaleString(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index c2c9aefd5f..36b1512b63 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -53,6 +53,13 @@ using namespace QV4;
const ManagedVTable ExecutionContext::static_vtbl =
{
+ ExecutionContext::IsExecutionContext,
+ ExecutionContext::IsString,
+ ExecutionContext::IsObject,
+ ExecutionContext::IsFunctionObject,
+ ExecutionContext::IsErrorObject,
+ 0,
+ ExecutionContext::MyType,
call,
construct,
markObjects,
@@ -70,6 +77,7 @@ const ManagedVTable ExecutionContext::static_vtbl =
0,
isEqualTo,
0,
+ 0,
"ExecutionContext",
};
@@ -349,16 +357,9 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value)
}
if (activation) {
- if (ctx->type == Type_QmlContext) {
+ if (ctx->type == Type_QmlContext || activation->hasOwnProperty(name)) {
activation->put(name, value);
return;
- } else {
- PropertyAttributes attrs;
- Property *p = activation->__getOwnProperty__(name, &attrs);
- if (p) {
- activation->putValue(p, attrs, value);
- return;
- }
}
}
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 334d033193..a0930a577e 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -70,6 +70,10 @@ struct WithContext;
struct Q_QML_EXPORT ExecutionContext : public Managed
{
Q_MANAGED
+ Q_MANAGED_TYPE(ExecutionContext)
+ enum {
+ IsExecutionContext = true
+ };
enum ContextType {
Type_GlobalContext = 0x1,
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 5d0c8ccf8e..2b6aa21ac2 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -647,7 +647,6 @@ DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date)
: Object(engine->dateClass)
{
setVTable(&static_vtbl);
- type = Type_DateObject;
value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN());
}
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 9c451dd251..244553b1d4 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -53,9 +53,9 @@ namespace QV4 {
struct DateObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(DateObject)
SafeValue value;
DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) {
- type = Type_DateObject;
value = date;
}
DateObject(ExecutionEngine *engine, const QDateTime &value);
@@ -64,8 +64,7 @@ struct DateObject: Object {
protected:
DateObject(InternalClass *ic): Object(ic) {
- setVTable(&static_vtbl);
- type = Type_DateObject;
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
value = Primitive::fromDouble(qSNaN());
}
};
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index ac18e56868..5de8e0de44 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -202,9 +202,9 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
identifierTable = new IdentifierTable(this);
emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this);
- executionContextClass = emptyClass->changeVTable(&ExecutionContext::static_vtbl);
- stringClass = emptyClass->changeVTable(&String::static_vtbl);
- regExpValueClass = emptyClass->changeVTable(&RegExp::static_vtbl);
+ executionContextClass = InternalClass::create(this, &ExecutionContext::static_vtbl, 0);
+ stringClass = InternalClass::create(this, &String::static_vtbl, 0);
+ regExpValueClass = InternalClass::create(this, &RegExp::static_vtbl, 0);
id_undefined = newIdentifier(QStringLiteral("undefined"));
id_null = newIdentifier(QStringLiteral("null"));
@@ -237,7 +237,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
id_toString = newIdentifier(QStringLiteral("toString"));
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
- ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass->changeVTable(&ObjectPrototype::static_vtbl));
+ ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(InternalClass::create(this, &ObjectPrototype::static_vtbl, 0));
objectClass = InternalClass::create(this, &Object::static_vtbl, objectPrototype);
Q_ASSERT(objectClass->vtable == &Object::static_vtbl);
@@ -256,16 +256,16 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
initRootContext();
- StringPrototype *stringPrototype = new (memoryManager) StringPrototype(objectClass);
+ StringPrototype *stringPrototype = new (memoryManager) StringPrototype(InternalClass::create(this, &StringPrototype::static_vtbl, objectPrototype));
stringObjectClass = InternalClass::create(this, &String::static_vtbl, stringPrototype);
- NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(objectClass);
+ NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(InternalClass::create(this, &NumberPrototype::static_vtbl, objectPrototype));
numberClass = InternalClass::create(this, &NumberObject::static_vtbl, numberPrototype);
- BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(objectClass);
+ BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(InternalClass::create(this, &BooleanPrototype::static_vtbl, objectPrototype));
booleanClass = InternalClass::create(this, &BooleanObject::static_vtbl, booleanPrototype);
- DatePrototype *datePrototype = new (memoryManager) DatePrototype(objectClass);
+ DatePrototype *datePrototype = new (memoryManager) DatePrototype(InternalClass::create(this, &DatePrototype::static_vtbl, objectPrototype));
dateClass = InternalClass::create(this, &DateObject::static_vtbl, datePrototype);
FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, &FunctionPrototype::static_vtbl, objectPrototype));
@@ -276,14 +276,14 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
protoClass = objectClass->addMember(id_constructor, Attr_NotEnumerable, &index);
Q_ASSERT(index == FunctionObject::Index_ProtoConstructor);
- RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(objectClass);
+ RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(InternalClass::create(this, &RegExpPrototype::static_vtbl, objectPrototype));
regExpClass = InternalClass::create(this, &RegExpObject::static_vtbl, regExpPrototype);
regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
- ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(objectClass);
+ ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(InternalClass::create(this, &ErrorObject::static_vtbl, objectPrototype));
errorClass = InternalClass::create(this, &ErrorObject::static_vtbl, errorPrototype);
EvalErrorPrototype *evalErrorPrototype = new (memoryManager) EvalErrorPrototype(errorClass);
evalErrorClass = InternalClass::create(this, &EvalErrorObject::static_vtbl, evalErrorPrototype);
@@ -364,8 +364,8 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor);
globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor);
ScopedObject o(scope);
- globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = new (memoryManager) MathObject(this)));
- globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = new (memoryManager) JsonObject(this)));
+ globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = new (memoryManager) MathObject(QV4::InternalClass::create(this, &MathObject::static_vtbl, objectPrototype))));
+ globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = new (memoryManager) JsonObject(QV4::InternalClass::create(this, &JsonObject::static_vtbl, objectPrototype))));
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue());
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN()));
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index cf5c06dd41..f5d21b2f30 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -76,8 +76,6 @@ ErrorObject::ErrorObject(InternalClass *ic)
: Object(ic)
, stack(0)
{
- type = Type_ErrorObject;
-
Scope scope(engine());
ScopedValue protectThis(scope, this);
@@ -89,7 +87,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t)
: Object(ic)
, stack(0)
{
- type = Type_ErrorObject;
subtype = t;
Scope scope(engine());
@@ -113,7 +110,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, ErrorObject:
: Object(ic)
, stack(0)
{
- type = Type_ErrorObject;
subtype = t;
Scope scope(engine());
@@ -137,7 +133,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QStrin
: Object(ic)
, stack(0)
{
- type = Type_ErrorObject;
subtype = t;
Scope scope(engine());
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index def776d3b6..560b003062 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -52,6 +52,10 @@ struct SyntaxErrorObject;
struct ErrorObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(ErrorObject)
+ enum {
+ IsErrorObject = true
+ };
enum ErrorType {
Error,
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index ce81282aa3..daa3d5b0de 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -112,7 +112,6 @@ FunctionObject::FunctionObject(InternalClass *ic)
{
name = ic->engine->id_undefined;
- type = Type_FunctionObject;
needsActivation = false;
strictMode = false;
}
@@ -130,7 +129,6 @@ void FunctionObject::init(const StringRef n, bool createProto)
Scope s(internalClass->engine);
ScopedValue protectThis(s, this);
- type = Type_FunctionObject;
needsActivation = true;
strictMode = false;
@@ -342,19 +340,19 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
if (!arg->isNullOrUndefined())
return ctx->throwTypeError();
} else {
- len = ArrayPrototype::getLength(ctx, arr);
+ len = arr->getLength();
}
ScopedCallData callData(scope, len);
if (len) {
- if (!(arr->flags & SimpleArray) || arr->protoHasArray() || arr->hasAccessorProperty) {
+ if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty) {
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
- int alen = qMin(len, arr->arrayDataLen);
+ int alen = qMin(len, arr->arrayData->length());
for (int i = 0; i < alen; ++i)
- callData->args[i] = arr->arrayData[i].value;
+ callData->args[i] = arr->arrayData->data[i].value;
for (quint32 i = alen; i < len; ++i)
callData->args[i] = Primitive::undefinedValue();
}
@@ -426,8 +424,8 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
- *insertMember(scope->engine->id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
- *insertMember(scope->engine->id_arguments, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
+ insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
}
@@ -508,8 +506,8 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
- *insertMember(scope->engine->id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
- *insertMember(scope->engine->id_arguments, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
+ insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
}
@@ -667,8 +665,8 @@ BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target,
ExecutionEngine *v4 = scope->engine;
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
- *insertMember(scope->engine->id_arguments, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
- *insertMember(scope->engine->id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
+ insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
void BoundFunction::destroy(Managed *that)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 96534cb68c..0168e13a6f 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -94,6 +94,10 @@ struct Lookup;
struct Q_QML_EXPORT FunctionObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(FunctionObject)
+ enum {
+ IsFunctionObject = true
+ };
// Used with Managed::subType
enum FunctionType {
RegularFunction = 0,
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 29ede3d104..761a180722 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -183,6 +183,8 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da
InternalClass *InternalClass::create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto)
{
InternalClass *c = engine->emptyClass->changeVTable(vtable);
+ if (!proto)
+ return c;
return c->changePrototype(proto);
}
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 6633435668..f40c765327 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -66,6 +66,8 @@ static int indent = 0;
#endif
+DEFINE_MANAGED_VTABLE(JsonObject);
+
class JsonParser
{
public:
@@ -288,8 +290,7 @@ bool JsonParser::parseMember(ObjectRef o)
if (idx < UINT_MAX) {
o->putIndexed(idx, val);
} else {
- Property *p = o->insertMember(s, Attr_Data);
- p->value = val.asReturnedValue();
+ o->insertMember(s, val);
}
END;
@@ -337,7 +338,7 @@ ReturnedValue JsonParser::parseArray()
}
}
- DEBUG << "size =" << array->arrayLength();
+ DEBUG << "size =" << array->getLength();
END;
--nestingLevel;
@@ -853,7 +854,7 @@ QString Stringify::JA(ArrayObjectRef a)
indent += gap;
QStringList partial;
- uint len = a->arrayLength();
+ uint len = a->getLength();
ScopedValue v(scope);
for (uint i = 0; i < len; ++i) {
bool exists;
@@ -884,12 +885,10 @@ QString Stringify::JA(ArrayObjectRef a)
}
-JsonObject::JsonObject(ExecutionEngine *engine)
- : Object(engine)
+JsonObject::JsonObject(InternalClass *ic)
+ : Object(ic)
{
- type = Type_JSONObject;
-
- Scope scope(engine);
+ Scope scope(ic->engine);
ScopedObject protectThis(scope, this);
defineDefaultProperty(QStringLiteral("parse"), method_parse, 2);
@@ -925,7 +924,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
if (o) {
stringify.replacerFunction = o->asFunctionObject();
if (o->isArrayObject()) {
- uint arrayLen = o->arrayLength();
+ uint arrayLen = o->getLength();
ScopedValue v(scope);
for (uint i = 0; i < arrayLen; ++i) {
v = o->getIndexed(i);
@@ -1057,9 +1056,10 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso
int size = array.size();
Scoped<ArrayObject> a(scope, engine->newArrayObject());
a->arrayReserve(size);
+ ScopedValue v(scope);
for (int i = 0; i < size; i++) {
- a->arrayData[i].value = fromJsonValue(engine, array.at(i));
- a->arrayDataLen = i + 1;
+ a->arrayData->put(i, (v = fromJsonValue(engine, array.at(i))));
+ a->arrayData->setLength(i + 1);
}
a->setArrayLengthUnchecked(size);
return a.asReturnedValue();
@@ -1083,7 +1083,7 @@ QJsonArray JsonObject::toJsonArray(ArrayObjectRef a, V4ObjectSet &visitedObjects
visitedObjects.insert(a);
ScopedValue v(scope);
- quint32 length = a->arrayLength();
+ quint32 length = a->getLength();
for (quint32 i = 0; i < length; ++i) {
v = a->getIndexed(i);
if (v->asFunctionObject())
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index 3bcbdeadbf..b37b28b078 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -51,10 +51,12 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct JsonObject : Object {
+ Q_MANAGED_TYPE(JsonObject)
+ Q_MANAGED
private:
typedef QSet<QV4::Object *> V4ObjectSet;
public:
- JsonObject(ExecutionEngine *engine);
+ JsonObject(InternalClass *ic);
static ReturnedValue method_parse(CallContext *ctx);
static ReturnedValue method_stringify(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index a870cdac61..66dc7b7e4a 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -316,6 +316,15 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, const ValueRef object)
return getterGeneric(l, object);
}
+ReturnedValue Lookup::arrayLengthGetter(Lookup *l, const ValueRef object)
+{
+ if (ArrayObject *a = object->asArrayObject())
+ return a->memberData[ArrayObject::LengthPropertyIndex].value.asReturnedValue();
+
+ l->getter = getterGeneric;
+ return getterGeneric(l, object);
+}
+
ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx)
{
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 9966d36604..93c2e2156e 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -85,6 +85,7 @@ struct Lookup {
static ReturnedValue primitiveGetterAccessor0(Lookup *l, const ValueRef object);
static ReturnedValue primitiveGetterAccessor1(Lookup *l, const ValueRef object);
static ReturnedValue stringLengthGetter(Lookup *l, const ValueRef object);
+ static ReturnedValue arrayLengthGetter(Lookup *l, const ValueRef object);
static ReturnedValue globalGetterGeneric(Lookup *l, ExecutionContext *ctx);
static ReturnedValue globalGetter0(Lookup *l, ExecutionContext *ctx);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index fef7489110..c3dec2535b 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -47,6 +47,13 @@ using namespace QV4;
const ManagedVTable Managed::static_vtbl =
{
+ Managed::IsExecutionContext,
+ Managed::IsString,
+ Managed::IsObject,
+ Managed::IsFunctionObject,
+ Managed::IsErrorObject,
+ 0,
+ Managed::MyType,
call,
construct,
0 /*markObjects*/,
@@ -64,6 +71,7 @@ const ManagedVTable Managed::static_vtbl =
0,
isEqualTo,
0,
+ 0,
"Managed",
};
@@ -101,7 +109,7 @@ ExecutionEngine *Managed::engine() const
QString Managed::className() const
{
const char *s = 0;
- switch (Type(type)) {
+ switch (Type(internalClass->vtable->type)) {
case Type_Invalid:
case Type_String:
return QString();
@@ -157,18 +165,23 @@ QString Managed::className() const
case Type_ArgumentsObject:
s = "Arguments";
break;
- case Type_JSONObject:
+ case Type_JsonObject:
s = "JSON";
break;
case Type_MathObject:
s = "Math";
break;
+
+ case Type_ExecutionContext:
+ s = "__ExecutionContext";
+ break;
case Type_ForeachIteratorObject:
s = "__ForeachIterator";
break;
case Type_RegExp:
- s = "RegExp";
+ s = "__RegExp";
break;
+
case Type_QmlSequence:
s = "QmlSequence";
break;
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index e10409f397..932dbe818c 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -53,8 +53,8 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
#define Q_MANAGED_CHECK \
- template <typename T> inline void qt_check_for_QMANAGED_macro(const T &_q_argument) const \
- { int i = qYouForgotTheQ_MANAGED_Macro(this, &_q_argument); i = i + 1; }
+ template <typename T> inline void qt_check_for_QMANAGED_macro(const T *_q_argument) const \
+ { int i = qYouForgotTheQ_MANAGED_Macro(this, _q_argument); i = i + 1; }
template <typename T>
inline int qYouForgotTheQ_MANAGED_Macro(T, T) { return 0; }
@@ -69,6 +69,9 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
template <typename T> \
QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \
+#define Q_MANAGED_TYPE(type) \
+ public: \
+ enum { MyType = Type_##type };
struct GCDeletable
{
@@ -80,6 +83,13 @@ struct GCDeletable
struct ManagedVTable
{
+ uint isExecutionContext : 1;
+ uint isString : 1;
+ uint isObject : 1;
+ uint isFunctionObject : 1;
+ uint isErrorObject : 1;
+ uint unused : 19;
+ uint type : 8;
ReturnedValue (*call)(Managed *, CallData *data);
ReturnedValue (*construct)(Managed *, CallData *data);
void (*markObjects)(Managed *, ExecutionEngine *e);
@@ -96,6 +106,7 @@ struct ManagedVTable
ReturnedValue (*getLookup)(Managed *m, Lookup *l);
void (*setLookup)(Managed *m, Lookup *l, const ValueRef v);
bool (*isEqualTo)(Managed *m, Managed *other);
+ uint (*getLength)(const Managed *m);
Property *(*advanceIterator)(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes);
const char *className;
};
@@ -103,6 +114,13 @@ struct ManagedVTable
#define DEFINE_MANAGED_VTABLE(classname) \
const QV4::ManagedVTable classname::static_vtbl = \
{ \
+ classname::IsExecutionContext, \
+ classname::IsString, \
+ classname::IsObject, \
+ classname::IsFunctionObject, \
+ classname::IsErrorObject, \
+ 0, \
+ classname::MyType, \
call, \
construct, \
markObjects, \
@@ -119,13 +137,52 @@ const QV4::ManagedVTable classname::static_vtbl = \
getLookup, \
setLookup, \
isEqualTo, \
+ getLength, \
advanceIterator, \
#classname \
}
+#define DEFINE_MANAGED_VTABLE_WITH_NAME(classname, name) \
+const QV4::ManagedVTable classname::static_vtbl = \
+{ \
+ classname::IsExecutionContext, \
+ classname::IsString, \
+ classname::IsObject, \
+ classname::IsFunctionObject, \
+ classname::IsErrorObject, \
+ 0, \
+ classname::MyType, \
+ call, \
+ construct, \
+ markObjects, \
+ destroy, \
+ 0, \
+ get, \
+ getIndexed, \
+ put, \
+ putIndexed, \
+ query, \
+ queryIndexed, \
+ deleteProperty, \
+ deleteIndexedProperty, \
+ getLookup, \
+ setLookup, \
+ isEqualTo, \
+ getLength, \
+ advanceIterator, \
+ #name \
+}
+
#define DEFINE_MANAGED_VTABLE_WITH_DELETABLES(classname) \
const QV4::ManagedVTable classname::static_vtbl = \
{ \
+ classname::IsExecutionContext, \
+ classname::IsString, \
+ classname::IsObject, \
+ classname::IsFunctionObject, \
+ classname::IsErrorObject, \
+ 0, \
+ classname::MyType, \
call, \
construct, \
markObjects, \
@@ -142,6 +199,7 @@ const QV4::ManagedVTable classname::static_vtbl = \
getLookup, \
setLookup, \
isEqualTo, \
+ getLength, \
advanceIterator, \
#classname \
}
@@ -149,6 +207,13 @@ const QV4::ManagedVTable classname::static_vtbl = \
struct Q_QML_EXPORT Managed
{
Q_MANAGED
+ enum {
+ IsExecutionContext = false,
+ IsString = false,
+ IsObject = false,
+ IsFunctionObject = false,
+ IsErrorObject = false
+ };
private:
void *operator new(size_t);
Managed(const Managed &other);
@@ -183,13 +248,16 @@ public:
Type_RegExpObject,
Type_ErrorObject,
Type_ArgumentsObject,
- Type_JSONObject,
+ Type_JsonObject,
Type_MathObject,
+
+ Type_ExecutionContext,
Type_ForeachIteratorObject,
Type_RegExp,
Type_QmlSequence
};
+ Q_MANAGED_TYPE(Invalid)
ExecutionEngine *engine() const;
@@ -199,7 +267,7 @@ public:
if (!this || !internalClass)
return 0;
#if !defined(QT_NO_QOBJECT_CHECK)
- static_cast<T *>(this)->qt_check_for_QMANAGED_macro(*static_cast<T *>(this));
+ static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(this));
#endif
return internalClass->vtable == &T::static_vtbl ? static_cast<T *>(this) : 0;
}
@@ -209,26 +277,26 @@ public:
if (!this)
return 0;
#if !defined(QT_NO_QOBJECT_CHECK)
- reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(const_cast<Managed *>(this)));
+ static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(const_cast<Managed *>(this)));
#endif
return internalClass->vtable == &T::static_vtbl ? static_cast<const T *>(this) : 0;
}
- String *asString() { return type == Type_String ? reinterpret_cast<String *>(this) : 0; }
- Object *asObject() { return type != Type_String ? reinterpret_cast<Object *>(this) : 0; }
- ArrayObject *asArrayObject() { return type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; }
- FunctionObject *asFunctionObject() { return type == Type_FunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; }
- BooleanObject *asBooleanObject() { return type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; }
- NumberObject *asNumberObject() { return type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; }
- StringObject *asStringObject() { return type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; }
- DateObject *asDateObject() { return type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; }
- ErrorObject *asErrorObject() { return type == Type_ErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; }
- ArgumentsObject *asArgumentsObject() { return type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; }
+ String *asString() { return internalClass->vtable->isString ? reinterpret_cast<String *>(this) : 0; }
+ Object *asObject() { return internalClass->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; }
+ ArrayObject *asArrayObject() { return internalClass->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; }
+ FunctionObject *asFunctionObject() { return internalClass->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; }
+ BooleanObject *asBooleanObject() { return internalClass->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; }
+ NumberObject *asNumberObject() { return internalClass->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; }
+ StringObject *asStringObject() { return internalClass->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; }
+ DateObject *asDateObject() { return internalClass->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; }
+ ErrorObject *asErrorObject() { return internalClass->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; }
+ ArgumentsObject *asArgumentsObject() { return internalClass->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; }
- bool isListType() const { return type == Type_QmlSequence; }
+ bool isListType() const { return internalClass->vtable->type == Type_QmlSequence; }
- bool isArrayObject() const { return type == Type_ArrayObject; }
- bool isStringObject() const { return type == Type_StringObject; }
+ bool isArrayObject() const { return internalClass->vtable->type == Type_ArrayObject; }
+ bool isStringObject() const { return internalClass->vtable->type == Type_StringObject; }
QString className() const;
@@ -263,6 +331,7 @@ public:
bool isEqualTo(Managed *other)
{ return internalClass->vtable->isEqualTo(this, other); }
+ uint getLength() const { return internalClass->vtable->getLength(this); }
Property *advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes);
static void destroy(Managed *that) { that->_data = 0; }
@@ -271,34 +340,27 @@ public:
static ReturnedValue getLookup(Managed *m, Lookup *);
static void setLookup(Managed *m, Lookup *l, const ValueRef v);
static bool isEqualTo(Managed *m, Managed *other);
-
- uint internalType() const {
- return type;
- }
+ static uint getLength(const Managed *) { return 0; }
ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); }
InternalClass *internalClass;
- enum {
- SimpleArray = 1
- };
-
union {
uint _data;
struct {
uchar markBit : 1;
uchar inUse : 1;
uchar extensible : 1; // used by Object
- uchar isNonStrictArgumentsObject : 1;
+ uchar _unused : 1;
uchar needsActivation : 1; // used by FunctionObject
uchar strictMode : 1; // used by FunctionObject
uchar bindingKeyFlag : 1;
uchar hasAccessorProperty : 1;
- uchar type;
+ uchar _type;
mutable uchar subtype;
- uchar flags;
+ uchar _flags;
};
};
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 5a7af1f041..6225d6b4ae 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -51,14 +51,14 @@
using namespace QV4;
+DEFINE_MANAGED_VTABLE(MathObject);
+
static const double qt_PI = 2.0 * ::asin(1.0);
-MathObject::MathObject(ExecutionEngine *engine)
- : Object(engine)
+MathObject::MathObject(InternalClass *ic)
+ : Object(ic)
{
- type = Type_MathObject;
-
- Scope scope(engine);
+ Scope scope(ic->engine);
ScopedObject protectThis(scope, this);
defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(::exp(1.0)));
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index 6fe3db3950..45f8e7cd2e 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -49,7 +49,9 @@ namespace QV4 {
struct MathObject: Object
{
- MathObject(ExecutionEngine *engine);
+ Q_MANAGED
+ Q_MANAGED_TYPE(MathObject)
+ MathObject(InternalClass *ic);
static ReturnedValue method_abs(CallContext *context);
static ReturnedValue method_acos(CallContext *context);
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 9923c8834c..d55ddead89 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -280,6 +280,7 @@ Managed *MemoryManager::alloc(std::size_t size)
if (size >= MemoryManager::Data::MaxItemSize) {
// we use malloc for this
MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem)));
+ memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem));
item->next = m_d->largeItems;
m_d->largeItems = item;
return item->managed();
@@ -525,6 +526,7 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size,
m->internalClass->vtable->collectDeletables(m, deletable);
m->internalClass->vtable->destroy(m);
+ memset(m, 0, size);
m->setNextFree(*f);
#ifdef V4_USE_VALGRIND
VALGRIND_DISABLE_ERROR_REPORTING;
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 106525d412..00d11b4cd6 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -72,37 +72,27 @@ DEFINE_MANAGED_VTABLE(Object);
Object::Object(ExecutionEngine *engine)
: Managed(engine->objectClass)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
- , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
{
- type = Type_Object;
- flags = SimpleArray;
- memset(memberData, 0, sizeof(Property)*memberDataAlloc);
}
Object::Object(InternalClass *ic)
: Managed(ic)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
- , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
{
Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl);
- type = Type_Object;
- flags = SimpleArray;
if (internalClass->size >= memberDataAlloc) {
memberDataAlloc = internalClass->size;
memberData = new Property[memberDataAlloc];
}
- memset(memberData, 0, sizeof(Property)*memberDataAlloc);
}
Object::~Object()
{
if (memberData != inlineProperties)
delete [] memberData;
- delete [] (arrayData - (sparseArray ? 0 : arrayOffset));
- if (arrayAttributes)
- delete [] (arrayAttributes - (sparseArray ? 0 : arrayOffset));
- delete sparseArray;
+ if (arrayData)
+ arrayData->free();
_data = 0;
}
@@ -172,12 +162,6 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val
engine()->currentContext()->throwTypeError();
}
-void Object::defineDefaultProperty(const StringRef name, ValueRef value)
-{
- Property *pd = insertMember(name, Attr_Data|Attr_NotEnumerable);
- pd->value = *value;
-}
-
void Object::defineDefaultProperty(const QString &name, ValueRef value)
{
ExecutionEngine *e = engine();
@@ -216,12 +200,10 @@ void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)
void Object::defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *v4 = engine();
- Property *p = insertMember(name, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- if (getter)
- p->setGetter(v4->newBuiltinFunction(v4->rootContext, name, getter)->getPointer());
- if (setter)
- p->setSetter(v4->newBuiltinFunction(v4->rootContext, name, setter)->getPointer());
+ Property p;
+ p.setGetter(getter ? v4->newBuiltinFunction(v4->rootContext, name, getter)->getPointer() : 0);
+ p.setSetter(setter ? v4->newBuiltinFunction(v4->rootContext, name, setter)->getPointer() : 0);
+ insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
void Object::defineReadonlyProperty(const QString &name, ValueRef value)
@@ -234,8 +216,7 @@ void Object::defineReadonlyProperty(const QString &name, ValueRef value)
void Object::defineReadonlyProperty(const StringRef name, ValueRef value)
{
- Property *pd = insertMember(name, Attr_ReadOnly);
- pd->value = *value;
+ insertMember(name, value, Attr_ReadOnly);
}
void Object::markObjects(Managed *that, ExecutionEngine *e)
@@ -258,23 +239,8 @@ void Object::markObjects(Managed *that, ExecutionEngine *e)
}
}
}
- if (o->flags & SimpleArray) {
- for (uint i = 0; i < o->arrayDataLen; ++i)
- o->arrayData[i].value.mark(e);
- return;
- } else {
- for (uint i = 0; i < o->arrayDataLen; ++i) {
- const Property &pd = o->arrayData[i];
- if (o->arrayAttributes && o->arrayAttributes[i].isAccessor()) {
- if (pd.getter())
- pd.getter()->mark(e);
- if (pd.setter())
- pd.setter()->mark(e);
- } else {
- pd.value.mark(e);
- }
- }
- }
+ if (o->arrayData)
+ o->arrayData->markObjects(e);
}
void Object::ensureMemberIndex(uint idx)
@@ -290,7 +256,7 @@ void Object::ensureMemberIndex(uint idx)
}
}
-Property *Object::insertMember(const StringRef s, PropertyAttributes attributes)
+void Object::insertMember(const StringRef s, const Property &p, PropertyAttributes attributes)
{
uint idx;
internalClass = internalClass->addMember(s.getPointer(), attributes, &idx);
@@ -300,7 +266,7 @@ Property *Object::insertMember(const StringRef s, PropertyAttributes attributes)
ensureMemberIndex(idx);
- return memberData + idx;
+ memberData[idx] = p;
}
// Section 8.12.1
@@ -324,14 +290,11 @@ Property *Object::__getOwnProperty__(const StringRef name, PropertyAttributes *a
Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
{
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- Property *p = arrayData + pidx;
- if (!p->value.isEmpty() && !(arrayAttributes && arrayAttributes[pidx].isGeneric())) {
- if (attrs)
- *attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
- return p;
- }
+ Property *p = arrayData->getProperty(index);
+ if (p) {
+ if (attrs)
+ *attrs = arrayData->attributes(index);
+ return p;
}
if (isStringObject()) {
if (attrs)
@@ -372,14 +335,11 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr
{
const Object *o = this;
while (o) {
- uint pidx = o->propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- Property *p = o->arrayData + pidx;
- if (!p->value.isEmpty()) {
- if (attrs)
- *attrs = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
- return p;
- }
+ Property *p = o->arrayData->getProperty(index);
+ if (p) {
+ if (attrs)
+ *attrs = o->arrayData->attributes(index);
+ return p;
}
if (o->isStringObject()) {
Property *p = static_cast<const StringObject *>(o)->getIndex(index);
@@ -426,6 +386,16 @@ bool Object::__hasProperty__(uint index) const
return false;
}
+bool Object::hasOwnProperty(const StringRef name) const
+{
+ return const_cast<Object *>(this)->__getOwnProperty__(name) != 0;
+}
+
+bool Object::hasOwnProperty(uint index) const
+{
+ return const_cast<Object *>(this)->__getOwnProperty__(index) != 0;
+}
+
ReturnedValue Object::get(Managed *m, const StringRef name, bool *hasProperty)
{
return static_cast<Object *>(m)->internalGet(name, hasProperty);
@@ -463,13 +433,9 @@ PropertyAttributes Object::query(const Managed *m, StringRef name)
PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
{
const Object *o = static_cast<const Object *>(m);
- uint pidx = o->propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- if (o->arrayAttributes)
- return o->arrayAttributes[pidx];
- if (!o->arrayData[pidx].value.isEmpty())
- return Attr_Data;
- }
+ if (o->arrayData->get(index) != Primitive::emptyValue().asReturnedValue())
+ return o->arrayData->attributes(index);
+
if (o->isStringObject()) {
Property *p = static_cast<const StringObject *>(o)->getIndex(index);
if (p)
@@ -570,41 +536,42 @@ Property *Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name
name = (String *)0;
*index = UINT_MAX;
- if (!it->arrayIndex)
- it->arrayNode = o->sparseArrayBegin();
-
- // sparse arrays
- if (it->arrayNode) {
- while (it->arrayNode != o->sparseArrayEnd()) {
- int k = it->arrayNode->key();
- uint pidx = it->arrayNode->value;
- Property *p = o->arrayData + pidx;
- it->arrayNode = it->arrayNode->nextNode();
- PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
- if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
- it->arrayIndex = k + 1;
- *index = k;
+ if (o->arrayData) {
+ if (!it->arrayIndex)
+ it->arrayNode = o->sparseBegin();
+
+ // sparse arrays
+ if (it->arrayNode) {
+ while (it->arrayNode != o->sparseEnd()) {
+ int k = it->arrayNode->key();
+ uint pidx = it->arrayNode->value;
+ Property *p = o->arrayData->data + pidx;
+ it->arrayNode = it->arrayNode->nextNode();
+ PropertyAttributes a = o->arrayData->attributes(k);
+ if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
+ it->arrayIndex = k + 1;
+ *index = k;
+ if (attrs)
+ *attrs = a;
+ return p;
+ }
+ }
+ it->arrayNode = 0;
+ it->arrayIndex = UINT_MAX;
+ }
+ // dense arrays
+ while (it->arrayIndex < o->arrayData->length()) {
+ Property *p = o->arrayData->data + it->arrayIndex;
+ PropertyAttributes a = o->arrayData->attributes(it->arrayIndex);
+ ++it->arrayIndex;
+ if (!p->value.isEmpty()
+ && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
+ *index = it->arrayIndex - 1;
if (attrs)
*attrs = a;
return p;
}
}
- it->arrayNode = 0;
- it->arrayIndex = UINT_MAX;
- }
- // dense arrays
- while (it->arrayIndex < o->arrayDataLen) {
- uint pidx = o->propertyIndexFromArrayIndex(it->arrayIndex);
- Property *p = o->arrayData + pidx;
- PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
- ++it->arrayIndex;
- if (!p->value.isEmpty()
- && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
- *index = it->arrayIndex - 1;
- if (attrs)
- *attrs = a;
- return p;
- }
}
while (it->memberIndex < o->internalClass->size) {
@@ -654,17 +621,14 @@ ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty)
ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
{
Property *pd = 0;
- PropertyAttributes attrs = Attr_Data;
+ PropertyAttributes attrs;
Object *o = this;
while (o) {
- uint pidx = o->propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- if (!o->arrayData[pidx].value.isEmpty()) {
- pd = o->arrayData + pidx;
- if (o->arrayAttributes)
- attrs = o->arrayAttributes[pidx];
- break;
- }
+ Property *p = o->arrayData->getProperty(index);
+ if (p) {
+ pd = p;
+ attrs = o->arrayData->attributes(index);
+ break;
}
if (o->isStringObject()) {
pd = static_cast<StringObject *>(o)->getIndex(index);
@@ -761,11 +725,8 @@ void Object::internalPut(const StringRef name, const ValueRef value)
return;
}
- {
- Property *p = insertMember(name, Attr_Data);
- p->value = *value;
- return;
- }
+ insertMember(name, value);
+ return;
reject:
if (engine()->currentContext()->strictMode) {
@@ -781,14 +742,11 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
if (internalClass->engine->hasException)
return;
- Property *pd = 0;
PropertyAttributes attrs;
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX && !arrayData[pidx].value.isEmpty()) {
- pd = arrayData + pidx;
- attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
- }
+ Property *pd = arrayData->getProperty(index);
+ if (pd)
+ attrs = arrayData->attributes(index);
if (!pd && isStringObject()) {
pd = static_cast<StringObject *>(this)->getIndex(index);
@@ -879,22 +837,8 @@ bool Object::internalDeleteIndexedProperty(uint index)
if (internalClass->engine->hasException)
return false;
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx == UINT_MAX)
- return true;
- if (arrayData[pidx].value.isEmpty())
- return true;
-
- if (!arrayAttributes || arrayAttributes[pidx].isConfigurable()) {
- arrayData[pidx].value = Primitive::emptyValue();
- if (arrayAttributes)
- arrayAttributes[pidx].clear();
- if (sparseArray) {
- arrayData[pidx].value.int_32 = arrayFreeList;
- arrayFreeList = pidx;
- }
+ if (!arrayData || arrayData->deleteIndex(index))
return true;
- }
if (engine()->currentContext()->strictMode)
engine()->currentContext()->throwTypeError();
@@ -954,9 +898,9 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
if (!extensible)
goto reject;
// clause 4
- Property *pd = insertMember(name, attrs);
- *pd = p;
- pd->fullyPopulated(&attrs);
+ Property pd = p;
+ pd.fullyPopulated(&attrs);
+ insertMember(name, pd, attrs);
return true;
}
@@ -969,20 +913,27 @@ reject:
bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs)
{
- Property *current = 0;
-
// 15.4.5.1, 4b
- if (isArrayObject() && index >= arrayLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ if (isArrayObject() && index >= getLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
goto reject;
- if (isNonStrictArgumentsObject)
+ if (ArgumentsObject::isNonStrictArgumentsObject(this))
return static_cast<ArgumentsObject *>(this)->defineOwnProperty(ctx, index, p, attrs);
+ return defineOwnProperty2(ctx, index, p, attrs);
+reject:
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return false;
+}
+
+bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs)
+{
+ Property *current = 0;
+
// Clause 1
{
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX && !arrayData[pidx].value.isEmpty())
- current = arrayData + pidx;
+ current = arrayData->getProperty(index);
if (!current && isStringObject())
current = static_cast<StringObject *>(this)->getIndex(index);
}
@@ -992,9 +943,15 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop
if (!extensible)
goto reject;
// clause 4
- Property *pd = arrayInsert(index, attrs);
- *pd = p;
- pd->fullyPopulated(&attrs);
+ Property pp(p);
+ pp.fullyPopulated(&attrs);
+ if (attrs == Attr_Data) {
+ Scope scope(ctx);
+ ScopedValue v(scope, pp.value);
+ arraySet(index, v);
+ } else {
+ arraySet(index, pp, attrs);
+ }
return true;
}
@@ -1011,11 +968,11 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, con
if (attrs.isEmpty())
return true;
- PropertyAttributes cattrs = Attr_Data;
+ PropertyAttributes cattrs;
if (!member.isNull())
cattrs = internalClass->propertyData[current - memberData];
- else if (arrayAttributes)
- cattrs = arrayAttributes[current - arrayData];
+ else
+ cattrs = arrayData->attrs ? arrayData->attrs[current - arrayData->data] : Attr_Data;
// clause 6
if (p.isSubset(attrs, *current, cattrs))
@@ -1071,10 +1028,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, con
if (!member.isNull()) {
internalClass = internalClass->changeMember(member.getPointer(), cattrs);
} else {
- if (cattrs != Attr_Data)
- ensureArrayAttributes();
- if (arrayAttributes)
- arrayAttributes[current - arrayData] = cattrs;
+ arrayData->setAttributes(current - arrayData->data, cattrs);
}
if (attrs.isAccessor())
hasAccessorProperty = 1;
@@ -1100,7 +1054,7 @@ void Object::copyArrayData(Object *other)
Scope scope(engine());
if (other->protoHasArray() || other->hasAccessorProperty) {
- uint len = other->arrayLength();
+ uint len = other->getLength();
Q_ASSERT(len);
ScopedValue v(scope);
@@ -1108,313 +1062,97 @@ void Object::copyArrayData(Object *other)
arraySet(i, (v = other->getIndexed(i)));
}
} else {
- arrayReserve(other->arrayDataLen);
- arrayDataLen = other->arrayDataLen;
- memcpy(arrayData, other->arrayData, arrayDataLen*sizeof(Property));
- }
-
- arrayOffset = 0;
+ Q_ASSERT(!arrayData && other->arrayData);
+ if (other->arrayType() == ArrayData::Sparse) {
+ SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData);
+ SparseArrayData *dd = new SparseArrayData;
+ dd->type = ArrayData::Sparse;
+ dd->sparse = new SparseArray(*od->sparse);
+ dd->freeList = od->freeList;
+ arrayData = dd;
+ }
+ arrayReserve(other->arrayData->len);
+ arrayData->len = other->arrayData->len;
+ // ### correctly deal with accessor properties
+ memcpy(arrayData->data, other->arrayData->data, arrayData->len*sizeof(Property));
- if (other->sparseArray) {
- flags &= ~SimpleArray;
- sparseArray = new SparseArray(*other->sparseArray);
- arrayFreeList = other->arrayFreeList;
+ arrayData->offset = 0;
}
-
- setArrayLengthUnchecked(other->arrayLength());
+ setArrayLengthUnchecked(other->getLength());
}
-
-ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
+uint Object::getLength(const Managed *m)
{
- Q_UNUSED(ctx);
-
- Scope scope(engine());
- ScopedValue value(scope);
-
- if (!(o->flags & SimpleArray) || o->protoHasArray()) {
- // lets be safe and slow
- for (uint i = fromIndex; i < endIndex; ++i) {
- bool exists;
- value = o->getIndexed(i, &exists);
- if (scope.hasException())
- return Encode::undefined();
- if (exists && __qmljs_strict_equal(value, v))
- return Encode(i);
- }
- } else if (sparseArray) {
- for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n != sparseArray->end() && n->key() < endIndex; n = n->nextNode()) {
- value = o->getValue(arrayData + n->value, arrayAttributes ? arrayAttributes[n->value] : Attr_Data);
- if (scope.hasException())
- return Encode::undefined();
- if (__qmljs_strict_equal(value, v))
- return Encode(n->key());
- }
- } else {
- if (endIndex > arrayDataLen)
- endIndex = arrayDataLen;
- Property *pd = arrayData;
- Property *end = pd + endIndex;
- pd += fromIndex;
- while (pd < end) {
- if (!pd->value.isEmpty()) {
- value = o->getValue(pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data);
- if (scope.hasException())
- return Encode::undefined();
- if (__qmljs_strict_equal(value, v))
- return Encode((uint)(pd - arrayData));
- }
- ++pd;
- }
- }
- return Encode(-1);
+ Scope scope(m->engine());
+ ScopedValue v(scope, const_cast<Managed *>(m)->get(scope.engine->id_length));
+ return v->toUInt32();
}
-void Object::arrayConcat(const ArrayObject *other)
+bool Object::setArrayLength(uint newLen)
{
- int newLen = arrayDataLen + other->arrayLength();
- if (other->sparseArray)
- initSparse();
- // ### copy attributes as well!
- if (sparseArray) {
- if (other->sparseArray) {
- for (const SparseArrayNode *it = other->sparseArray->begin(); it != other->sparseArray->end(); it = it->nextNode())
- arraySet(arrayDataLen + it->key(), other->arrayData + it->value);
- } else {
- int oldSize = arrayDataLen;
- arrayReserve(oldSize + other->arrayLength());
- memcpy(arrayData + oldSize, other->arrayData, other->arrayLength()*sizeof(Property));
- if (arrayAttributes)
- std::fill(arrayAttributes + oldSize, arrayAttributes + oldSize + other->arrayLength(), PropertyAttributes(Attr_Data));
- for (uint i = 0; i < other->arrayLength(); ++i) {
- SparseArrayNode *n = sparseArray->insert(arrayDataLen + i);
- n->value = oldSize + i;
- }
- }
+ Q_ASSERT(isArrayObject());
+ const Property *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
+ if (lengthProperty && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ return false;
+ uint oldLen = getLength();
+ bool ok = true;
+ if (newLen < oldLen) {
+ uint l = arrayData->truncate(newLen);
+ if (l != newLen)
+ ok = false;
+ newLen = l;
} else {
- uint oldSize = arrayLength();
- arrayReserve(oldSize + other->arrayDataLen);
- if (oldSize > arrayDataLen) {
- for (uint i = arrayDataLen; i < oldSize; ++i)
- arrayData[i].value = Primitive::emptyValue();
- }
- if (other->arrayAttributes) {
- for (uint i = 0; i < other->arrayDataLen; ++i) {
- bool exists;
- arrayData[oldSize + i].value = const_cast<ArrayObject *>(other)->getIndexed(i, &exists);
- arrayDataLen = oldSize + i + 1;
- if (arrayAttributes)
- arrayAttributes[oldSize + i] = Attr_Data;
- if (!exists)
- arrayData[oldSize + i].value = Primitive::emptyValue();
- }
- } else {
- arrayDataLen = oldSize + other->arrayDataLen;
- memcpy(arrayData + oldSize, other->arrayData, other->arrayDataLen*sizeof(Property));
- if (arrayAttributes)
- std::fill(arrayAttributes + oldSize, arrayAttributes + oldSize + other->arrayDataLen, PropertyAttributes(Attr_Data));
- }
+ if (newLen >= 0x100000)
+ initSparseArray();
}
setArrayLengthUnchecked(newLen);
+ return ok;
}
-void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint len)
+void Object::initSparseArray()
{
- if (!arrayDataLen)
+ if (arrayType() == ArrayData::Sparse)
return;
- if (sparseArray) {
- context->throwUnimplemented(QStringLiteral("Object::sort unimplemented for sparse arrays"));
+ SparseArrayData *data = new SparseArrayData;
+ data->type = ArrayData::Sparse;
+ data->sparse = new SparseArray;
+ if (!arrayData) {
+ arrayData = data;
return;
}
- if (len > arrayDataLen)
- len = arrayDataLen;
-
- // The spec says the sorting goes through a series of get,put and delete operations.
- // this implies that the attributes don't get sorted around.
- // behavior of accessor properties is implementation defined. We simply turn them all
- // into data properties and then sort. This is in line with the sentence above.
- if (arrayAttributes) {
- for (uint i = 0; i < len; i++) {
- if ((arrayAttributes && arrayAttributes[i].isGeneric()) || arrayData[i].value.isEmpty()) {
- while (--len > i)
- if (!((arrayAttributes && arrayAttributes[len].isGeneric())|| arrayData[len].value.isEmpty()))
- break;
- arrayData[i].value = getValue(arrayData + len, arrayAttributes[len]);
- arrayData[len].value = Primitive::emptyValue();
- if (arrayAttributes) {
- arrayAttributes[i] = Attr_Data;
- arrayAttributes[len].clear();
- }
- } else if (arrayAttributes[i].isAccessor()) {
- arrayData[i].value = getValue(arrayData + i, arrayAttributes[i]);
- arrayAttributes[i] = Attr_Data;
- }
- }
- }
-
- if (!(comparefn->isUndefined() || comparefn->asObject())) {
- context->throwTypeError();
- return;
+ uint oldOffset = arrayData->offset;
+ data->data = arrayData->data - arrayData->offset;
+ data->attrs = arrayData->attrs;
+ data->len = arrayData->len;
+ data->alloc = arrayData->alloc;
+ data->offset = 0;
+ arrayData->data = 0;
+ arrayData->attrs = 0;
+ delete arrayData;
+
+ uint *lastFree = &data->freeList;
+ for (uint i = 0; i < oldOffset; ++i) {
+ *lastFree = i;
+ lastFree = &data->data[i].value.uint_32;
}
-
- ArrayElementLessThan lessThan(context, thisObject, comparefn);
-
- if (!len)
- return;
- Property *begin = arrayData;
- std::sort(begin, begin + len, lessThan);
-}
-
-
-void Object::initSparse()
-{
- if (!sparseArray) {
- flags &= ~SimpleArray;
- sparseArray = new SparseArray;
- for (uint i = 0; i < arrayDataLen; ++i) {
- if (!((arrayAttributes && arrayAttributes[i].isGeneric()) || arrayData[i].value.isEmpty())) {
- SparseArrayNode *n = sparseArray->insert(i);
- n->value = i + arrayOffset;
- }
- }
-
- uint off = arrayOffset;
- if (!arrayOffset) {
- arrayFreeList = arrayDataLen;
+ for (uint i = 0; i < data->len; ++i) {
+ if (!data->data[i + oldOffset].value.isEmpty()) {
+ SparseArrayNode *n = data->sparse->insert(i);
+ n->value = i + oldOffset;
} else {
- arrayFreeList = 0;
- arrayData -= off;
- arrayAlloc += off;
- int o = off;
- for (int i = 0; i < o - 1; ++i) {
- arrayData[i].value = Primitive::fromInt32(i + 1);
- }
- arrayData[o - 1].value = Primitive::fromInt32(arrayDataLen + off);
- }
- for (uint i = arrayDataLen + off; i < arrayAlloc; ++i) {
- arrayData[i].value = Primitive::fromInt32(i + 1);
+ *lastFree = i + oldOffset;
+ lastFree = &data->data[i + oldOffset].value.uint_32;
}
}
-}
-
-void Object::arrayReserve(uint n)
-{
- if (n < 8)
- n = 8;
- if (n >= arrayAlloc) {
- uint off;
- if (sparseArray) {
- assert(arrayFreeList == arrayAlloc);
- // ### FIXME
- arrayDataLen = arrayAlloc;
- off = 0;
- } else {
- off = arrayOffset;
- }
- arrayAlloc = qMax(n, 2*arrayAlloc);
- Property *newArrayData = new Property[arrayAlloc + off];
- if (arrayData) {
- memcpy(newArrayData + off, arrayData, sizeof(Property)*arrayDataLen);
- delete [] (arrayData - off);
- }
- arrayData = newArrayData + off;
- if (sparseArray) {
- for (uint i = arrayFreeList; i < arrayAlloc; ++i) {
- arrayData[i].value = Primitive::emptyValue();
- arrayData[i].value = Primitive::fromInt32(i + 1);
- }
- }
-
- if (arrayAttributes) {
- PropertyAttributes *newAttrs = new PropertyAttributes[arrayAlloc];
- memcpy(newAttrs, arrayAttributes, sizeof(PropertyAttributes)*arrayDataLen);
- delete [] (arrayAttributes - off);
-
- arrayAttributes = newAttrs;
- if (sparseArray) {
- for (uint i = arrayFreeList; i < arrayAlloc; ++i)
- arrayAttributes[i] = Attr_Invalid;
- }
- }
+ for (uint i = data->len + oldOffset; i < data->alloc; ++i) {
+ *lastFree = i;
+ lastFree = &data->data[i].value.uint_32;
}
+ arrayData = data;
}
-void Object::ensureArrayAttributes()
-{
- if (arrayAttributes)
- return;
-
- flags &= ~SimpleArray;
- uint off = sparseArray ? 0 : arrayOffset;
- arrayAttributes = new PropertyAttributes[arrayAlloc + off];
- arrayAttributes += off;
- for (uint i = 0; i < arrayDataLen; ++i)
- arrayAttributes[i] = Attr_Data;
- for (uint i = arrayDataLen; i < arrayAlloc; ++i)
- arrayAttributes[i] = Attr_Invalid;
-}
-
-
-bool Object::setArrayLength(uint newLen) {
- assert(isArrayObject());
- const Property *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
- if (lengthProperty && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
- return false;
- uint oldLen = arrayLength();
- bool ok = true;
- if (newLen < oldLen) {
- if (sparseArray) {
- SparseArrayNode *begin = sparseArray->lowerBound(newLen);
- if (begin != sparseArray->end()) {
- SparseArrayNode *it = sparseArray->end()->previousNode();
- while (1) {
- Property &pd = arrayData[it->value];
- if (arrayAttributes) {
- if (!arrayAttributes[it->value].isConfigurable()) {
- ok = false;
- newLen = it->key() + 1;
- break;
- } else {
- arrayAttributes[it->value].clear();
- }
- }
- pd.value.tag = Value::Empty_Type;
- pd.value.int_32 = arrayFreeList;
- arrayFreeList = it->value;
- bool brk = (it == begin);
- SparseArrayNode *prev = it->previousNode();
- sparseArray->erase(it);
- if (brk)
- break;
- it = prev;
- }
- }
- } else {
- Property *it = arrayData + arrayDataLen;
- const Property *begin = arrayData + newLen;
- while (--it >= begin) {
- if (arrayAttributes) {
- if (!arrayAttributes[it - arrayData].isEmpty() && !arrayAttributes[it - arrayData].isConfigurable()) {
- ok = false;
- newLen = it - arrayData + 1;
- break;
- } else {
- arrayAttributes[it - arrayData].clear();
- }
- it->value = Primitive::emptyValue();
- }
- }
- arrayDataLen = newLen;
- }
- } else {
- if (newLen >= 0x100000)
- initSparse();
- }
- setArrayLengthUnchecked(newLen);
- return ok;
-}
DEFINE_MANAGED_VTABLE(ArrayObject);
@@ -1431,9 +1169,10 @@ ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
// elements converted to JS Strings.
int len = list.count();
arrayReserve(len);
+ ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii) {
- arrayData[ii].value = Encode(engine->newString(list.at(ii)));
- arrayDataLen = ii + 1;
+ arrayData->put(ii, (v = engine->newString(list.at(ii))));
+ arrayData->setLength(ii + 1);
}
setArrayLengthUnchecked(len);
}
@@ -1442,10 +1181,28 @@ void ArrayObject::init(ExecutionEngine *engine)
{
Q_UNUSED(engine);
- type = Type_ArrayObject;
memberData[LengthPropertyIndex].value = Primitive::fromInt32(0);
}
+ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l)
+{
+ if (l->name->equals(m->engine()->id_length)) {
+ // special case, as the property is on the object itself
+ l->getter = Lookup::arrayLengthGetter;
+ ArrayObject *a = static_cast<ArrayObject *>(m);
+ return a->memberData[ArrayObject::LengthPropertyIndex].value.asReturnedValue();
+ }
+ return Object::getLookup(m, l);
+}
+
+uint ArrayObject::getLength(const Managed *m)
+{
+ const ArrayObject *a = static_cast<const ArrayObject *>(m);
+ if (a->memberData[ArrayObject::LengthPropertyIndex].value.isInteger())
+ return a->memberData[ArrayObject::LengthPropertyIndex].value.integerValue();
+ return Primitive::toUInt32(a->memberData[ArrayObject::LengthPropertyIndex].value.doubleValue());
+}
+
QStringList ArrayObject::toQStringList() const
{
QStringList result;
@@ -1454,7 +1211,7 @@ QStringList ArrayObject::toQStringList() const
Scope scope(engine);
ScopedValue v(scope);
- uint32_t length = arrayLength();
+ uint32_t length = getLength();
for (uint32_t i = 0; i < length; ++i) {
v = const_cast<ArrayObject *>(this)->getIndexed(i);
result.append(v->toQStringNoThrow());
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 23f2f682fd..9500c2a4d0 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -49,7 +49,7 @@
#include "qv4managed_p.h"
#include "qv4property_p.h"
#include "qv4internalclass_p.h"
-#include "qv4sparsearray_p.h"
+#include "qv4arraydata_p.h"
#include <QtCore/QString>
#include <QtCore/QHash>
@@ -100,20 +100,17 @@ struct SyntaxErrorPrototype;
struct TypeErrorPrototype;
struct URIErrorPrototype;
+
struct Q_QML_EXPORT Object: Managed {
Q_MANAGED
+ Q_MANAGED_TYPE(Object)
+ enum {
+ IsObject = true
+ };
uint memberDataAlloc;
Property *memberData;
- union {
- uint arrayFreeList;
- uint arrayOffset;
- };
- uint arrayDataLen;
- uint arrayAlloc;
- PropertyAttributes *arrayAttributes;
- Property *arrayData;
- SparseArray *sparseArray;
+ ArrayData *arrayData;
enum {
InlinePropertySize = 4
@@ -136,10 +133,14 @@ struct Q_QML_EXPORT Object: Managed {
bool __hasProperty__(const StringRef name) const;
bool __hasProperty__(uint index) const;
+ bool hasOwnProperty(const StringRef name) const;
+ bool hasOwnProperty(uint index) const;
+
bool __defineOwnProperty__(ExecutionContext *ctx, Property *current, const StringRef member, const Property &p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionContext *ctx, const StringRef name, const Property &p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs);
+ bool defineOwnProperty2(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs);
//
// helpers
@@ -156,7 +157,9 @@ struct Q_QML_EXPORT Object: Managed {
void putValue(Property *pd, PropertyAttributes attrs, const ValueRef value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
- void defineDefaultProperty(const StringRef name, ValueRef value);
+ void defineDefaultProperty(const StringRef name, ValueRef value) {
+ insertMember(name, value, Attr_Data|Attr_NotEnumerable);
+ }
void defineDefaultProperty(const QString &name, ValueRef value);
void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
void defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
@@ -166,113 +169,63 @@ struct Q_QML_EXPORT Object: Managed {
void defineReadonlyProperty(const QString &name, ValueRef value);
void defineReadonlyProperty(const StringRef name, ValueRef value);
- Property *insertMember(const StringRef s, PropertyAttributes attributes);
+ void insertMember(const StringRef s, const ValueRef v, PropertyAttributes attributes = Attr_Data) {
+ insertMember(s, Property::fromValue(*v), attributes);
+ }
+ void insertMember(const StringRef s, const Property &p, PropertyAttributes attributes);
inline ExecutionEngine *engine() const { return internalClass->engine; }
// Array handling
- uint allocArrayValue() {
- uint idx = arrayFreeList;
- if (arrayAlloc <= arrayFreeList)
- arrayReserve(arrayAlloc + 1);
- arrayFreeList = arrayData[arrayFreeList].value.uint_32;
- if (arrayAttributes)
- arrayAttributes[idx].setType(PropertyAttributes::Data);
- return idx;
- }
-
- uint allocArrayValue(const ValueRef v) {
- uint idx = allocArrayValue();
- Property *pd = &arrayData[idx];
- pd->value = *v;
- return idx;
- }
- void freeArrayValue(int idx) {
- Property &pd = arrayData[idx];
- pd.value.tag = Value::Empty_Type;
- pd.value.int_32 = arrayFreeList;
- arrayFreeList = idx;
- if (arrayAttributes)
- arrayAttributes[idx].clear();
- }
-
- void getArrayHeadRoom() {
- assert(!sparseArray && !arrayOffset);
- arrayOffset = qMax(arrayDataLen >> 2, (uint)16);
- Property *newArray = new Property[arrayOffset + arrayAlloc];
- memcpy(newArray + arrayOffset, arrayData, arrayDataLen*sizeof(Property));
- delete [] arrayData;
- arrayData = newArray + arrayOffset;
- if (arrayAttributes) {
- PropertyAttributes *newAttrs = new PropertyAttributes[arrayOffset + arrayAlloc];
- memcpy(newAttrs + arrayOffset, arrayAttributes, arrayDataLen*sizeof(PropertyAttributes));
- delete [] arrayAttributes;
- arrayAttributes = newAttrs + arrayOffset;
- }
- }
-
public:
void copyArrayData(Object *other);
- void initSparse();
- uint arrayLength() const;
bool setArrayLength(uint newLen);
void setArrayLengthUnchecked(uint l);
- Property *arrayInsert(uint index, PropertyAttributes attributes = Attr_Data);
+ void arraySet(uint index, const Property &p, PropertyAttributes attributes = Attr_Data);
- void arraySet(uint index, const Property *pd);
void arraySet(uint index, ValueRef value);
- uint propertyIndexFromArrayIndex(uint index) const
- {
- if (!sparseArray) {
- if (index >= arrayDataLen)
- return UINT_MAX;
- return index;
- } else {
- SparseArrayNode *n = sparseArray->findNode(index);
- if (!n)
- return UINT_MAX;
- return n->value;
- }
- }
+ void push_back(const ValueRef v);
- Property *arrayAt(uint index) const {
- uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx == UINT_MAX)
- return 0;
- return arrayData + pidx;
+ ArrayData::Type arrayType() const {
+ return arrayData ? (ArrayData::Type)arrayData->type : ArrayData::Simple;
}
-
- Property *nonSparseArrayAt(uint index) const {
- if (sparseArray)
- return 0;
- if (index >= arrayDataLen)
- return 0;
- return arrayData + index;
+ // ### remove me
+ void setArrayType(ArrayData::Type t) {
+ Q_ASSERT(t != ArrayData::Simple && t != ArrayData::Sparse);
+ arrayCreate();
+ arrayData->type = t;
}
- void push_back(const ValueRef v);
+ inline void arrayReserve(uint n) {
+ arrayCreate();
+ arrayData->vtable->reserve(arrayData, n);
+ }
- SparseArrayNode *sparseArrayBegin() { return sparseArray ? sparseArray->begin() : 0; }
- SparseArrayNode *sparseArrayEnd() { return sparseArray ? sparseArray->end() : 0; }
+ void arrayCreate() {
+ if (!arrayData)
+ arrayData = new ArrayData;
+ }
- void arrayConcat(const ArrayObject *other);
- void arraySort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint arrayDataLen);
- ReturnedValue arrayIndexOf(const ValueRef v, uint fromIndex, uint arrayDataLen, ExecutionContext *ctx, Object *o);
+ void initSparseArray();
+ SparseArrayNode *sparseBegin() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData)->sparse->begin() : 0; }
+ SparseArrayNode *sparseEnd() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData)->sparse->end() : 0; }
- void arrayReserve(uint n);
- void ensureArrayAttributes();
+ inline Property *arrayInsert(uint index) {
+ arrayCreate();
+ return ArrayData::insert(this, index);
+ }
inline bool protoHasArray() {
Scope scope(engine());
Scoped<Object> p(scope, this);
while ((p = p->prototype()))
- if (p->arrayDataLen)
+ if (p->arrayData)
return true;
return false;
@@ -298,6 +251,7 @@ public:
using Managed::getLookup;
using Managed::setLookup;
using Managed::advanceIterator;
+ using Managed::getLength;
protected:
static void destroy(Managed *that);
static void markObjects(Managed *that, ExecutionEngine *e);
@@ -312,7 +266,7 @@ protected:
static ReturnedValue getLookup(Managed *m, Lookup *l);
static void setLookup(Managed *m, Lookup *l, const ValueRef v);
static Property *advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes);
-
+ static uint getLength(const Managed *m);
private:
ReturnedValue internalGet(const StringRef name, bool *hasProperty);
@@ -328,40 +282,39 @@ private:
struct BooleanObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(BooleanObject)
SafeValue value;
BooleanObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->booleanClass) {
- type = Type_BooleanObject;
value = val;
}
protected:
BooleanObject(InternalClass *ic)
: Object(ic) {
- setVTable(&static_vtbl);
- type = Type_BooleanObject;
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
value = Encode(false);
}
};
struct NumberObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(NumberObject)
SafeValue value;
NumberObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->numberClass) {
- type = Type_NumberObject;
value = val;
}
protected:
NumberObject(InternalClass *ic)
: Object(ic) {
- setVTable(&static_vtbl);
- type = Type_NumberObject;
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
value = Encode((int)0);
}
};
struct ArrayObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(ArrayObject)
enum {
LengthPropertyIndex = 0
};
@@ -372,19 +325,13 @@ struct ArrayObject: Object {
void init(ExecutionEngine *engine);
+ static ReturnedValue getLookup(Managed *m, Lookup *l);
+ using Managed::getLength;
+ static uint getLength(const Managed *m);
+
QStringList toQStringList() const;
};
-inline uint Object::arrayLength() const
-{
- if (isArrayObject()) {
- if (memberData[ArrayObject::LengthPropertyIndex].value.isInteger())
- return memberData[ArrayObject::LengthPropertyIndex].value.integerValue();
- return Primitive::toUInt32(memberData[ArrayObject::LengthPropertyIndex].value.doubleValue());
- }
- return 0;
-}
-
inline void Object::setArrayLengthUnchecked(uint l)
{
if (isArrayObject()) {
@@ -396,64 +343,35 @@ inline void Object::setArrayLengthUnchecked(uint l)
inline void Object::push_back(const ValueRef v)
{
- uint idx = arrayLength();
- if (!sparseArray) {
- if (idx >= arrayAlloc)
- arrayReserve(idx + 1);
- arrayData[idx].value = *v;
- arrayDataLen = idx + 1;
- } else {
- uint idx = allocArrayValue(v);
- sparseArray->push_back(idx, arrayLength());
- }
+ arrayCreate();
+ Q_ASSERT(!arrayData->isSparse());
+
+ uint idx = getLength();
+ arrayReserve(idx + 1);
+ arrayData->put(idx, v);
+ arrayData->setLength(idx + 1);
setArrayLengthUnchecked(idx + 1);
}
-inline Property *Object::arrayInsert(uint index, PropertyAttributes attributes) {
+inline void Object::arraySet(uint index, const Property &p, PropertyAttributes attributes)
+{
if (attributes.isAccessor())
hasAccessorProperty = 1;
- Property *pd;
- if (!sparseArray && (index < 0x1000 || index < arrayDataLen + (arrayDataLen >> 2))) {
- if (index >= arrayAlloc)
- arrayReserve(index + 1);
- if (index >= arrayDataLen) {
- // mark possible hole in the array
- for (uint i = arrayDataLen; i < index; ++i) {
- arrayData[i].value = Primitive::emptyValue();
- if (arrayAttributes)
- arrayAttributes[i].clear();
- }
- arrayDataLen = index + 1;
- }
- pd = arrayData + index;
- } else {
- initSparse();
- SparseArrayNode *n = sparseArray->insert(index);
- if (n->value == UINT_MAX)
- n->value = allocArrayValue();
- pd = arrayData + n->value;
- }
- if (index >= arrayLength())
+ Property *pd = arrayInsert(index);
+ *pd = p;
+ arrayData->setAttributes(index, attributes);
+ if (isArrayObject() && index >= getLength())
setArrayLengthUnchecked(index + 1);
- if (arrayAttributes || attributes != Attr_Data) {
- if (!arrayAttributes)
- ensureArrayAttributes();
- attributes.resolve();
- arrayAttributes[pd - arrayData] = attributes;
- }
- return pd;
}
+
inline void Object::arraySet(uint index, ValueRef value)
{
Property *pd = arrayInsert(index);
- pd->value = *value;
-}
-
-inline void Object::arraySet(uint index, const Property *pd)
-{
- *arrayInsert(index) = *pd;
+ pd->value = value ? *value : Primitive::undefinedValue();
+ if (isArrayObject() && index >= getLength())
+ setArrayLengthUnchecked(index + 1);
}
template<>
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 04fa504991..f7a5cd7531 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -58,7 +58,7 @@ ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
- if (object && object->isNonStrictArgumentsObject) {
+ if (object && object->asArgumentsObject()) {
Scope scope(object->engine());
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
}
@@ -76,7 +76,7 @@ ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
- if (object && object->isNonStrictArgumentsObject) {
+ if (object && object->asArgumentsObject()) {
Scope scope(object->engine());
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 6c333b328c..33228cefaa 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -86,11 +86,11 @@ struct Q_QML_EXPORT ObjectIterator
struct ForEachIteratorObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(ForeachIteratorObject)
ObjectIterator it;
ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o)
: Object(ctx->engine), it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
setVTable(&static_vtbl);
- type = Type_ForeachIteratorObject;
}
ReturnedValue nextPropertyName() { return it.nextPropertyNameAsString(); }
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 7ca790b970..ac19101a29 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -105,9 +105,9 @@ ReturnedValue ObjectCtor::call(Managed *m, CallData *callData)
void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
{
Scope scope(v4);
- ScopedObject o(scope);
+ ScopedObject o(scope, this);
- ctor->defineReadonlyProperty(v4->id_prototype, (o = this));
+ ctor->defineReadonlyProperty(v4->id_prototype, o);
ctor->defineReadonlyProperty(v4->id_length, Primitive::fromInt32(1));
ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
@@ -134,9 +134,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2);
Scoped<String> id_proto(scope, v4->id___proto__);
- Property *p = insertMember(StringRef(v4->id___proto__), Attr_Accessor|Attr_NotEnumerable);
- p->setGetter(v4->newBuiltinFunction(v4->rootContext, id_proto, method_get_proto)->getPointer());
- p->setSetter(v4->newBuiltinFunction(v4->rootContext, id_proto, method_set_proto)->getPointer());
+ Property p = Property::fromAccessor(v4->newBuiltinFunction(v4->rootContext, id_proto, method_get_proto)->getPointer(),
+ v4->newBuiltinFunction(v4->rootContext, id_proto, method_set_proto)->getPointer());
+ insertMember(StringRef(v4->id___proto__), p, Attr_Accessor|Attr_NotEnumerable);
}
ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx)
@@ -157,7 +157,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
if (!O)
return ctx->throwTypeError();
- if (O->isNonStrictArgumentsObject)
+ if (ArgumentsObject::isNonStrictArgumentsObject(O.getPointer()))
Scoped<ArgumentsObject>(scope, O)->fullyCreate();
ScopedValue v(scope, ctx->argument(1));
@@ -271,10 +271,12 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
o->internalClass = o->internalClass->sealed();
- o->ensureArrayAttributes();
- for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
- o->arrayAttributes[i].setConfigurable(false);
+ if (o->arrayData) {
+ o->arrayData->ensureAttributes();
+ for (uint i = 0; i < o->arrayData->length(); ++i) {
+ if (!o->arrayData->isEmpty(i))
+ o->arrayData->attrs[i].setConfigurable(false);
+ }
}
return o.asReturnedValue();
@@ -287,19 +289,21 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- if (o->isNonStrictArgumentsObject)
+ if (ArgumentsObject::isNonStrictArgumentsObject(o.getPointer()))
Scoped<ArgumentsObject>(scope, o)->fullyCreate();
o->extensible = false;
o->internalClass = o->internalClass->frozen();
- o->ensureArrayAttributes();
- for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
- o->arrayAttributes[i].setConfigurable(false);
- if (o->arrayAttributes[i].isData())
- o->arrayAttributes[i].setWritable(false);
+ if (o->arrayData) {
+ o->arrayData->ensureAttributes();
+ for (uint i = 0; i < o->arrayData->length(); ++i) {
+ if (!o->arrayData->isEmpty(i))
+ o->arrayData->attrs[i].setConfigurable(false);
+ if (o->arrayData->attrs[i].isData())
+ o->arrayData->attrs[i].setWritable(false);
+ }
}
return o.asReturnedValue();
}
@@ -328,15 +332,16 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
if (o->internalClass != o->internalClass->sealed())
return Encode(false);
- if (!o->arrayDataLen)
+ if (!o->arrayData || !o->arrayData->length())
return Encode(true);
- if (!o->arrayAttributes)
+ if (o->arrayData->length() && !o->arrayData->attrs)
return Encode(false);
- for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
- if (o->arrayAttributes[i].isConfigurable())
+ for (uint i = 0; i < o->arrayData->length(); ++i) {
+ // ### Fix for sparse arrays
+ if (!o->arrayData->isEmpty(i))
+ if (o->arrayData->attributes(i).isConfigurable())
return Encode(false);
}
@@ -356,15 +361,16 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
if (o->internalClass != o->internalClass->frozen())
return Encode(false);
- if (!o->arrayDataLen)
+ if (!o->arrayData->length())
return Encode(true);
- if (!o->arrayAttributes)
+ if (o->arrayData->length() && !o->arrayData->attrs)
return Encode(false);
- for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
- if (o->arrayAttributes[i].isConfigurable() || o->arrayAttributes[i].isWritable())
+ for (uint i = 0; i < o->arrayData->length(); ++i) {
+ // ### Fix for sparse arrays
+ if (!o->arrayData->isEmpty(i))
+ if (o->arrayData->attributes(i).isConfigurable() || o->arrayData->attributes(i).isWritable())
return Encode(false);
}
@@ -448,7 +454,7 @@ ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx)
Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
if (scope.engine->hasException)
return Encode::undefined();
- bool r = O->__getOwnProperty__(P) != 0;
+ bool r = O->hasOwnProperty(P);
if (!r)
r = !O->query(P).isEmpty();
return Encode(r);
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 9763de5adf..ff9ea59514 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -53,7 +53,7 @@ struct FunctionObject;
struct Property {
union {
- Value value;
+ SafeValue value;
struct {
FunctionObject *get;
FunctionObject *set;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 61f92a0f5c..bad2cf3cd4 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1592,7 +1592,7 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::ValueRe
if (array) {
Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
- uint32_t length = array->arrayLength();
+ uint32_t length = array->getLength();
for (uint32_t ii = 0; ii < length; ++ii) {
QObject *o = 0;
qobjectWrapper = array->getIndexed(ii);
@@ -1689,9 +1689,10 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine)
QList<QObject *> &list = *qlistPtr;
QV4::Scoped<ArrayObject> array(scope, v4->newArrayObject());
array->arrayReserve(list.count());
+ QV4::ScopedValue v(scope);
for (int ii = 0; ii < list.count(); ++ii) {
- array->arrayData[ii].value = QV4::QObjectWrapper::wrap(v4, list.at(ii));
- array->arrayDataLen = ii + 1;
+ array->arrayData->put(ii, (v = QV4::QObjectWrapper::wrap(v4, list.at(ii))));
+ array->arrayData->setLength(ii + 1);
}
array->setArrayLengthUnchecked(list.count());
return array.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 41ff9f9741..8544970347 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -99,8 +99,6 @@ RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase,
, m_ignoreCase(ignoreCase)
, m_multiLine(multiline)
{
- type = Type_RegExpObject;
-
if (!engine)
return;
const char* error = 0;
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index 9041ff2ef4..d8e9930876 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -94,6 +94,7 @@ public:
class RegExp : public Managed
{
Q_MANAGED
+ Q_MANAGED_TYPE(RegExp)
public:
static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false);
~RegExp();
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 468fb34d76..1b55c5a2f1 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -76,6 +76,7 @@ RegExpObject::RegExpObject(InternalClass *ic)
, value(RegExp::create(ic->engine, QString(), false, false))
, global(false)
{
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
init(ic->engine);
}
@@ -143,14 +144,13 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
void RegExpObject::init(ExecutionEngine *engine)
{
setVTable(&static_vtbl);
- type = Type_RegExpObject;
Scope scope(engine);
ScopedObject protectThis(scope, this);
ScopedString lastIndex(scope, engine->newIdentifier(QStringLiteral("lastIndex")));
- Property *lastIndexProperty = insertMember(lastIndex, Attr_NotEnumerable|Attr_NotConfigurable);
- lastIndexProperty->value = Primitive::fromInt32(0);
+ ScopedValue v(scope, Primitive::fromInt32(0));
+ insertMember(lastIndex, v, Attr_NotEnumerable|Attr_NotConfigurable);
if (!this->value)
return;
@@ -162,7 +162,6 @@ void RegExpObject::init(ExecutionEngine *engine)
p.replace('/', QLatin1String("\\/"));
}
- ScopedValue v(scope);
defineReadonlyProperty(QStringLiteral("source"), (v = engine->newString(p)));
defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global));
defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value->ignoreCase()));
@@ -344,11 +343,13 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
Scoped<ArrayObject> array(scope, ctx->engine->newArrayObject(ctx->engine->regExpExecArrayClass));
int len = r->value->captureCount();
array->arrayReserve(len);
+ ScopedValue v(scope);
for (int i = 0; i < len; ++i) {
int start = matchOffsets[i * 2];
int end = matchOffsets[i * 2 + 1];
- array->arrayData[i].value = (start != -1 && end != -1) ? ctx->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
- array->arrayDataLen = i + 1;
+ v = (start != -1 && end != -1) ? ctx->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
+ array->arrayData->put(i, v);
+ array->arrayData->setLength(i + 1);
}
array->setArrayLengthUnchecked(len);
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 0129f8d396..bd91e8f693 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -67,6 +67,7 @@ class RegExp;
struct RegExpObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(RegExpObject)
// needs to be compatible with the flags in qv4jsir_p.h
enum Flags {
RegExp_Global = 0x01,
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 011607f0ba..9275704984 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -589,12 +589,10 @@ ReturnedValue __qmljs_get_element(ExecutionContext *ctx, const ValueRef object,
}
if (idx < UINT_MAX) {
- uint pidx = o->propertyIndexFromArrayIndex(idx);
- if (pidx < UINT_MAX) {
- if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
- if (!o->arrayData[pidx].value.isEmpty())
- return o->arrayData[pidx].value.asReturnedValue();
- }
+ if (!o->arrayData->hasAttributes()) {
+ ScopedValue v(scope, o->arrayData->get(idx));
+ if (!v->isEmpty())
+ return v->asReturnedValue();
}
return o->getIndexed(idx);
@@ -615,36 +613,10 @@ void __qmljs_set_element(ExecutionContext *ctx, const ValueRef object, const Val
uint idx = index->asArrayIndex();
if (idx < UINT_MAX) {
- uint pidx = o->propertyIndexFromArrayIndex(idx);
- if (pidx < UINT_MAX) {
- if (o->arrayAttributes && !o->arrayAttributes[pidx].isEmpty() && !o->arrayAttributes[pidx].isWritable()) {
- if (ctx->strictMode)
- ctx->throwTypeError();
- return;
- }
-
- Property *p = o->arrayData + pidx;
- if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
- p->value = *value;
- return;
- }
-
- if (o->arrayAttributes[pidx].isAccessor()) {
- FunctionObject *setter = p->setter();
- if (!setter) {
- if (ctx->strictMode)
- ctx->throwTypeError();
- return;
- }
-
- ScopedCallData callData(scope, 1);
- callData->thisObject = o;
- callData->args[0] = *value;
- setter->call(callData);
- return;
- }
- }
- o->putIndexed(idx, value);
+ if (idx < o->arrayData->length() && o->arrayType() == ArrayData::Simple)
+ o->arrayData->put(idx, value);
+ else
+ o->putIndexed(idx, value);
return;
}
@@ -1118,25 +1090,23 @@ void __qmljs_builtin_define_property(ExecutionContext *ctx, const ValueRef objec
assert(o);
uint idx = name->asArrayIndex();
- Property *pd = (idx != UINT_MAX) ? o->arrayInsert(idx) : o->insertMember(name, Attr_Data);
- pd->value = val ? *val : Primitive::undefinedValue();
+ if (idx != UINT_MAX) {
+ o->arraySet(idx, val);
+ } else {
+ ScopedValue v(scope, val ? *val : Primitive::undefinedValue());
+ o->insertMember(name, v);
+ }
}
-ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, Value *values, uint length)
+ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, SafeValue *values, uint length)
{
Scope scope(ctx);
Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
- // ### FIXME: We need to allocate the array data to avoid crashes other places
- // This should rather be done when required
- a->arrayReserve(length);
if (length) {
- a->arrayDataLen = length;
- Property *pd = a->arrayData;
- for (uint i = 0; i < length; ++i) {
- pd->value = values[i];
- ++pd;
- }
+ a->arrayReserve(length);
+ a->arrayData->setLength(length);
+ a->arrayData->put(0, values, length);
a->setArrayLengthUnchecked(length);
}
return a.asReturnedValue();
@@ -1149,9 +1119,14 @@ void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const ValueRef
Q_ASSERT(!!o);
uint idx = name->asArrayIndex();
- Property *pd = (idx != UINT_MAX) ? o->arrayInsert(idx, Attr_Accessor) : o->insertMember(name, Attr_Accessor);
- pd->setGetter(getter ? getter->asFunctionObject() : 0);
- pd->setSetter(setter ? setter->asFunctionObject() : 0);
+ Property pd;
+ pd.setGetter(getter ? getter->asFunctionObject() : 0);
+ pd.setSetter(setter ? setter->asFunctionObject() : 0);
+ if (idx != UINT_MAX) {
+ o->arraySet(idx, pd, Attr_Accessor);
+ } else {
+ o->insertMember(name, pd, Attr_Accessor);
+ }
}
ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId)
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 9524b2459c..2e252b1067 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -141,7 +141,7 @@ QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx);
ReturnedValue __qmljs_builtin_unwind_exception(ExecutionContext *ctx);
void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, const QV4::StringRef name);
void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, QV4::ValueRef val);
-QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *values, uint length);
+QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, SafeValue *values, uint length);
void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, const QV4::ValueRef getter, const QV4::ValueRef setter);
QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId);
QV4::ReturnedValue __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 8b0e31cb71..feb3806ba5 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -166,6 +166,7 @@ template <typename Container>
class QQmlSequence : public QV4::Object
{
Q_MANAGED
+ Q_MANAGED_TYPE(QmlSequence)
public:
QQmlSequence(QV4::ExecutionEngine *engine, const Container &container)
: QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject()))
@@ -174,8 +175,7 @@ public:
, m_propertyIndex(-1)
, m_isReference(false)
{
- type = Type_QmlSequence;
- flags &= ~SimpleArray;
+ setArrayType(ArrayData::Custom);
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
Q_UNUSED(protectThis);
@@ -188,8 +188,7 @@ public:
, m_propertyIndex(propertyIndex)
, m_isReference(true)
{
- type = Type_QmlSequence;
- flags &= ~SimpleArray;
+ setArrayType(ArrayData::Custom);
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
Q_UNUSED(protectThis);
@@ -469,7 +468,7 @@ public:
{
QV4::Scope scope(array->engine());
Container result;
- quint32 length = array->arrayLength();
+ quint32 length = array->getLength();
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < length; ++i)
result << convertValueToElement<typename Container::value_type>((v = array->getIndexed(i)));
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index ee325db4c2..5f9e24d89c 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -183,7 +183,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
push(data, valueheader(WorkerUndefined));
} else if (v->asArrayObject()) {
QV4::ScopedArrayObject array(scope, v);
- uint32_t length = array->arrayLength();
+ uint32_t length = array->getLength();
if (length > 0xFFFFFF) {
push(data, valueheader(WorkerUndefined));
return;
@@ -266,7 +266,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
// regular object
QV4::ScopedValue val(scope, *v);
QV4::ScopedArrayObject properties(scope, QV4::ObjectPrototype::getOwnPropertyNames(v4, val));
- quint32 length = properties->arrayLength();
+ quint32 length = properties->getLength();
if (length > 0xFFFFFF) {
push(data, valueheader(WorkerUndefined));
return;
@@ -390,8 +390,8 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine)
array->arrayReserve(seqLength);
for (quint32 ii = 0; ii < seqLength; ++ii) {
value = deserialize(data, engine);
- array->arrayData[ii].value = value.asReturnedValue();
- array->arrayDataLen = ii + 1;
+ array->arrayData->put(ii, value);
+ array->arrayData->setLength(ii + 1);
}
array->setArrayLengthUnchecked(seqLength);
QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded);
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index e5633eb06f..df48faf601 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -103,6 +103,13 @@ static uint toArrayIndex(const char *ch, const char *end, bool *ok)
const ManagedVTable String::static_vtbl =
{
+ String::IsExecutionContext,
+ String::IsString,
+ String::IsObject,
+ String::IsFunctionObject,
+ String::IsErrorObject,
+ 0,
+ String::MyType,
call,
construct,
markObjects,
@@ -119,6 +126,7 @@ const ManagedVTable String::static_vtbl =
0 /*getLookup*/,
0 /*setLookup*/,
isEqualTo,
+ 0,
0 /*advanceIterator*/,
"String",
};
@@ -233,10 +241,9 @@ bool String::isEqualTo(Managed *t, Managed *o)
if (t == o)
return true;
- if (o->type != Type_String)
+ if (!o->internalClass->vtable->isString)
return false;
- Q_ASSERT(t->type == Type_String);
String *that = static_cast<String *>(t);
String *other = static_cast<String *>(o);
if (that->hashValue() != other->hashValue())
@@ -257,7 +264,6 @@ String::String(ExecutionEngine *engine, const QString &text)
{
_text->ref.ref();
len = _text->size;
- type = Type_String;
subtype = StringType_Unknown;
}
@@ -267,7 +273,6 @@ String::String(ExecutionEngine *engine, String *l, String *r)
, stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength))
, len(l->len + r->len)
{
- type = Type_String;
subtype = StringType_Unknown;
if (!l->largestSubLength && l->len > largestSubLength)
@@ -418,3 +423,8 @@ uint String::toArrayIndex(const QString &str)
bool ok;
return ::toArrayIndex(str.constData(), str.constData() + str.length(), &ok);
}
+
+uint String::getLength(const Managed *m)
+{
+ return static_cast<const String *>(m)->length();
+}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 64e15b04c2..bc5b30518e 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -53,6 +53,11 @@ struct Identifier;
struct Q_QML_EXPORT String : public Managed {
Q_MANAGED
+ Q_MANAGED_TYPE(String)
+ enum {
+ IsString = true
+ };
+
enum StringType {
StringType_Unknown,
StringType_Regular,
@@ -63,7 +68,7 @@ struct Q_QML_EXPORT String : public Managed {
String()
: Managed(0), _text(QStringData::sharedNull()), identifier(0)
, stringHash(UINT_MAX), largestSubLength(0), len(0)
- { type = Type_String; subtype = StringType_Unknown; }
+ { subtype = StringType_Unknown; }
String(ExecutionEngine *engine, const QString &text);
String(ExecutionEngine *engine, String *l, String *n);
~String() {
@@ -86,6 +91,7 @@ struct Q_QML_EXPORT String : public Managed {
return toQString() == other->toQString();
}
+
inline bool compare(const String *other) {
return toQString() < other->toQString();
}
@@ -167,6 +173,7 @@ protected:
static bool deleteProperty(Managed *, const StringRef);
static bool deleteIndexedProperty(Managed *m, uint index);
static bool isEqualTo(Managed *that, Managed *o);
+ static uint getLength(const Managed *m);
private:
QChar *recursiveAppend(QChar *ch) const;
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index d468fb6b83..1781ce2581 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -80,8 +80,7 @@ DEFINE_MANAGED_VTABLE(StringObject);
StringObject::StringObject(InternalClass *ic)
: Object(ic)
{
- setVTable(&static_vtbl);
- type = Type_StringObject;
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
Scope scope(engine());
ScopedObject protectThis(scope, this);
@@ -97,7 +96,6 @@ StringObject::StringObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->stringObjectClass)
{
setVTable(&static_vtbl);
- type = Type_StringObject;
Scope scope(engine);
ScopedObject protectThis(scope, this);
@@ -146,14 +144,20 @@ Property *StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRe
while (it->arrayIndex < slen) {
*index = it->arrayIndex;
++it->arrayIndex;
- if (attrs)
- *attrs = s->arrayAttributes ? s->arrayAttributes[it->arrayIndex] : PropertyAttributes(Attr_NotWritable|Attr_NotConfigurable);
- return s->__getOwnProperty__(*index);
+ PropertyAttributes a;
+ Property *p = s->__getOwnProperty__(*index, &a);
+ if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
+ if (attrs)
+ *attrs = a;
+ return p;
+ }
+ }
+ if (s->arrayData) {
+ it->arrayNode = s->sparseBegin();
+ // iterate until we're past the end of the string
+ while (it->arrayNode && it->arrayNode->key() < slen)
+ it->arrayNode = it->arrayNode->nextNode();
}
- it->arrayNode = s->sparseArrayBegin();
- // iterate until we're past the end of the string
- while (it->arrayNode && it->arrayNode->key() < slen)
- it->arrayNode = it->arrayNode->nextNode();
}
return Object::advanceIterator(m, it, name, index, attrs);
@@ -694,18 +698,18 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
array->push_back((s = ctx->engine->newString(text.mid(offset, matchOffsets[0] - offset))));
offset = qMax(offset + 1, matchOffsets[1]);
- if (array->arrayLength() >= limit)
+ if (array->getLength() >= limit)
break;
for (int i = 1; i < re->value->captureCount(); ++i) {
uint start = matchOffsets[i * 2];
uint end = matchOffsets[i * 2 + 1];
array->push_back((s = ctx->engine->newString(text.mid(start, end - start))));
- if (array->arrayLength() >= limit)
+ if (array->getLength() >= limit)
break;
}
}
- if (array->arrayLength() < limit)
+ if (array->getLength() < limit)
array->push_back((s = ctx->engine->newString(text.mid(offset))));
} else {
QString separator = separatorValue->toString(ctx)->toQString();
@@ -720,10 +724,10 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
while ((end = text.indexOf(separator, start)) != -1) {
array->push_back((s = ctx->engine->newString(text.mid(start, end - start))));
start = end + separator.size();
- if (array->arrayLength() >= limit)
+ if (array->getLength() >= limit)
break;
}
- if (array->arrayLength() < limit && start != -1)
+ if (array->getLength() < limit && start != -1)
array->push_back((s = ctx->engine->newString(text.mid(start))));
}
return array.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index e8e46b85e7..b91cc48e36 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -51,6 +51,7 @@ namespace QV4 {
struct StringObject: Object {
Q_MANAGED
+ Q_MANAGED_TYPE(StringObject)
SafeValue value;
mutable Property tmpProperty;
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 680c7465ca..b93fcbe4bd 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -64,13 +64,13 @@ inline bool Value::isString() const
{
if (!isManaged())
return false;
- return managed() && managed()->type == Managed::Type_String;
+ return managed() && managed()->internalClass->vtable->isString;
}
inline bool Value::isObject() const
{
if (!isManaged())
return false;
- return managed() && managed()->type != Managed::Type_String;
+ return managed() && managed()->internalClass->vtable->isObject;
}
inline bool Value::isPrimitive() const
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h
index 820ae8ed71..29103930ad 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/parser/qqmljsmemorypool_p.h
@@ -108,6 +108,8 @@ public:
_ptr = _end = 0;
}
+ template <typename _Tp> _Tp *New() { return new (this->allocate(sizeof(_Tp))) _Tp(); }
+
private:
void *allocate_helper(size_t size)
{
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 9e2fb07066..9b83feebb4 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -146,7 +146,8 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
typeData->release();
}
- }
+ } else
+ code = scriptPrivate->script;
setNotifyOnValueChanged(true);
QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 3dd9d6a14d..069345ecd3 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -2614,7 +2614,7 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
if (isIntProp) {
// Allow enum assignment to ints.
bool ok;
- int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
+ int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok);
if (ok) {
v->type = Value::Literal;
v->value = QQmlScript::Variant((double)enumval);
@@ -2665,46 +2665,38 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
return true;
}
-// Similar logic to above, but not knowing target property.
-int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
+int QQmlCompiler::bindingIdentifier(const QString &name, const Variant &value, const BindingContext &ctxt)
{
- Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
- *ok = false;
+ JSBindingReference *reference = pool->New<JSBindingReference>();
+ reference->expression = value;
+ reference->property = pool->New<Property>();
+ reference->property->setName(name);
+ reference->value = 0;
+ reference->bindingContext = ctxt;
+ reference->bindingContext.owner++;
+ // Unfortunately this is required for example for PropertyChanges where the bindings
+ // will be executed in the dynamic scope of the target, so we can't resolve any lookups
+ // at run-time.
+ reference->disableLookupAcceleration = true;
- if (scope != QLatin1String("Qt")) {
- QQmlType *type = 0;
- unit->imports().resolveType(scope, &type, 0, 0, 0);
- return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
- }
+ const int id = output->customParserBindings.count();
+ output->customParserBindings.append(0); // Filled in later.
+ reference->customParserBindingsIndex = id;
- const QMetaObject *mo = StaticQtMetaObject::get();
- int i = mo->enumeratorCount();
- while (i--) {
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
- if (*ok)
- return v;
- }
- return -1;
-}
+ compileState->totalBindingsCount++;
+ compileState->bindings.prepend(reference);
-const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
-{
- QQmlType *qmltype = 0;
- if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0))
- return 0;
- if (!qmltype)
- return 0;
- return qmltype->metaObject();
+ return id;
}
-int QQmlCompiler::bindingIdentifier(const QString &name, const Variant &value, const BindingContext &ctxt)
+QQmlBinding::Identifier QQmlCompiler::bindingIdentifier(const Variant &value, const QString &name, QQmlCustomParser *customParser)
{
JSBindingReference *reference = pool->New<JSBindingReference>();
reference->expression = value;
reference->property = pool->New<Property>();
reference->property->setName(name);
reference->value = 0;
- reference->bindingContext = ctxt;
+ reference->bindingContext = QQmlCompilerTypes::BindingContext(customParser->object);
reference->bindingContext.owner++;
// Unfortunately this is required for example for PropertyChanges where the bindings
// will be executed in the dynamic scope of the target, so we can't resolve any lookups
@@ -2882,7 +2874,7 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
Object::DynamicProperty::Type dtype;
int metaType;
} builtinTypes[] = {
- { Object::DynamicProperty::Var, QMetaType::QVariant },
+ { Object::DynamicProperty::Var, qMetaTypeId<QJSValue>() },
{ Object::DynamicProperty::Variant, QMetaType::QVariant },
{ Object::DynamicProperty::Int, QMetaType::Int },
{ Object::DynamicProperty::Bool, QMetaType::Bool },
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 516f6653ca..788def0288 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -65,6 +65,7 @@
#include <private/qqmlcodegenerator_p.h>
#include "private/qv4identifier_p.h"
#include <private/qqmljsastfwd_p.h>
+#include "qqmlcustomparser_p.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qset.h>
@@ -144,9 +145,9 @@ public:
QQmlPropertyCache *rootPropertyCache;
QList<QString> primitives;
- QList<QByteArray> datas;
+ QVector<QByteArray> datas;
QByteArray bytecode;
- QList<QQmlPropertyCache *> propertyCaches;
+ QVector<QQmlPropertyCache *> propertyCaches;
QList<QVector<QQmlContextData::ObjectIdMapping> > contextCaches;
QList<QQmlScriptData *> scripts;
QList<QUrl> urls;
@@ -157,6 +158,8 @@ public:
// 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;
+ // hash key is object index
+ QHash<int, QByteArray> customParserData;
QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
@@ -330,7 +333,7 @@ namespace QQmlCompilerTypes {
};
class QMetaObjectBuilder;
-class Q_AUTOTEST_EXPORT QQmlCompiler
+class Q_AUTOTEST_EXPORT QQmlCompiler : public QQmlCustomParserCompilerBackend
{
Q_DECLARE_TR_FUNCTIONS(QQmlCompiler)
public:
@@ -346,9 +349,10 @@ public:
static bool isAttachedPropertyName(const QHashedStringRef &);
static bool isSignalPropertyName(const QHashedStringRef &);
- int evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const; // for QQmlCustomParser::evaluateEnum
- const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType
int bindingIdentifier(const QString &name, const QQmlScript::Variant& value, const QQmlCompilerTypes::BindingContext &ctxt); // for QQmlCustomParser::bindingIndex
+ virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&value, const QString&name, QQmlCustomParser *customParser);
+
+ virtual const QQmlImports &imports() const { return unit->imports(); }
private:
typedef QQmlCompiledData::Instruction Instruction;
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 21bcd3569c..5813415347 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1056,7 +1056,11 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
p->compiledData = d->cc;
p->compiledData->addref();
- p->vme.init(contextData, d->cc, d->start, d->creationContext);
+ if (enginePriv->useNewCompiler) {
+ p->creator.reset(new QmlObjectCreator(contextData, d->cc));
+ p->subComponentToCreate = d->start;
+ } else
+ p->vme.init(contextData, d->cc, d->start, d->creationContext);
enginePriv->incubate(incubator, forContextData);
}
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 19e49009ce..ca23451774 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -230,6 +230,13 @@ void QQmlCustomParser::clearErrors()
exceptions.clear();
}
+QByteArray QQmlCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+{
+ Q_UNUSED(qmlUnit)
+ Q_UNUSED(bindings)
+ return QByteArray();
+}
+
/*!
Reports an error with the given \a description.
@@ -256,7 +263,6 @@ void QQmlCustomParser::error(const QString& description)
void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString& description)
{
QQmlError error;
- QString exceptionDescription;
error.setLine(prop.location().line);
error.setColumn(prop.location().column);
error.setDescription(description);
@@ -271,7 +277,6 @@ void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString
void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& description)
{
QQmlError error;
- QString exceptionDescription;
error.setLine(node.location().line);
error.setColumn(node.location().column);
error.setDescription(description);
@@ -279,6 +284,34 @@ void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& de
}
/*!
+ Reports an error in parsing \a binding, with the given \a description.
+
+ An error is generated referring to the position of \a node in the source file.
+*/
+void QQmlCustomParser::error(const QV4::CompiledData::Binding *binding, const QString &description)
+{
+ QQmlError error;
+ error.setLine(binding->location.line);
+ error.setColumn(binding->location.column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ Reports an error in parsing \a object, with the given \a description.
+
+ An error is generated referring to the position of \a object in the source file.
+*/
+void QQmlCustomParser::error(const QV4::CompiledData::Object *object, const QString &description)
+{
+ QQmlError error;
+ error.setLine(object->location.line);
+ error.setColumn(object->location.column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
If \a script is a simple enumeration expression (eg. Text.AlignLeft),
returns the integer equivalent (eg. 1), and sets \a ok to true.
@@ -313,7 +346,44 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
*/
QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QQmlScript::Variant &value, const QString& name)
{
- return compiler->bindingIdentifier(name, value, QQmlCompilerTypes::BindingContext(object));
+ return compiler->bindingIdentifier(value, name, this);
+}
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+};
+
+int QQmlCustomParserCompilerBackend::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
+{
+ Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
+ *ok = false;
+
+ if (scope != QLatin1String("Qt")) {
+ QQmlType *type = 0;
+ imports().resolveType(scope, &type, 0, 0, 0);
+ return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ }
+
+ const QMetaObject *mo = StaticQtMetaObject::get();
+ int i = mo->enumeratorCount();
+ while (i--) {
+ int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ if (*ok)
+ return v;
+ }
+ return -1;
+}
+
+const QMetaObject *QQmlCustomParserCompilerBackend::resolveType(const QString &name) const
+{
+ QQmlType *qmltype = 0;
+ if (!imports().resolveType(name, &qmltype, 0, 0, 0))
+ return 0;
+ if (!qmltype)
+ return 0;
+ return qmltype->metaObject();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 27f7e00b31..2f1a9ddec8 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -108,6 +108,17 @@ private:
QQmlCustomParserNodePrivate *d;
};
+struct QQmlCustomParserCompilerBackend
+{
+ virtual ~QQmlCustomParserCompilerBackend() {}
+ virtual const QQmlImports &imports() const = 0;
+
+ int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const;
+ const QMetaObject *resolveType(const QString& name) const;
+
+ virtual QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&, QQmlCustomParser *) { return QQmlBinding::Invalid; }
+};
+
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
{
public:
@@ -126,6 +137,7 @@ public:
Flags flags() const { return m_flags; }
virtual QByteArray compile(const QList<QQmlCustomParserProperty> &)=0;
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); // ### make pure virtual
virtual void setCustomData(QObject *, const QByteArray &)=0;
QList<QQmlError> errors() const { return exceptions; }
@@ -134,6 +146,8 @@ protected:
void error(const QString& description);
void error(const QQmlCustomParserProperty&, const QString& description);
void error(const QQmlCustomParserNode&, const QString& description);
+ void error(const QV4::CompiledData::Binding *binding, const QString& description);
+ void error(const QV4::CompiledData::Object *object, const QString& description);
int evaluateEnum(const QByteArray&, bool *ok) const;
@@ -143,10 +157,11 @@ protected:
private:
QList<QQmlError> exceptions;
- QQmlCompiler *compiler;
+ QQmlCustomParserCompilerBackend *compiler;
QQmlScript::Object *object;
Flags m_flags;
friend class QQmlCompiler;
+ friend class QQmlPropertyValidator;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags)
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index ade4634c2d..52bf1d8b3e 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -46,6 +46,7 @@
#include "qqmlcompiler_p.h"
#include "qqmlexpression_p.h"
#include "qqmlmemoryprofiler_p.h"
+#include "qqmlobjectcreator_p.h"
// XXX TODO
// - check that the Component.onCompleted behavior is the same as 4.8 in the synchronous and
@@ -292,7 +293,14 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
if (progress == QQmlIncubatorPrivate::Execute) {
enginePriv->referenceScarceResources();
- QObject *tresult = vme.execute(&errors, i);
+ QObject *tresult = 0;
+ if (enginePriv->useNewCompiler) {
+ tresult = creator->create(subComponentToCreate);
+ if (!tresult)
+ errors = creator->errors;
+ } else {
+ tresult = vme.execute(&errors, i);
+ }
enginePriv->dereferenceScarceResources();
if (watcher.hasRecursed())
@@ -335,7 +343,11 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
if (watcher.hasRecursed())
return;
- QQmlContextData *ctxt = vme.complete(i);
+ QQmlContextData *ctxt = 0;
+ if (enginePriv->useNewCompiler)
+ ctxt = creator->finalize();
+ else
+ ctxt = vme.complete(i);
if (ctxt) {
rootContext = ctxt;
progress = QQmlIncubatorPrivate::Completed;
@@ -566,6 +578,7 @@ void QQmlIncubator::clear()
d->vme.reset();
d->vmeGuard.clear();
+ d->creator.reset(0);
Q_ASSERT(d->compiledData == 0);
Q_ASSERT(d->waitingOnMe.data() == 0);
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index e7246ce3b2..a8b549bd28 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -88,7 +88,12 @@ public:
QPointer<QObject> result;
QQmlGuardedContextData rootContext;
QQmlCompiledData *compiledData;
+ // --- old compiler
QQmlVME vme;
+ // --- new compiler
+ QScopedPointer<QmlObjectCreator> creator;
+ int subComponentToCreate;
+ // ---
QQmlVMEGuard vmeGuard;
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> waitingOnMe;
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 7b975c2cc8..76c11cb748 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -57,7 +57,7 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine)
v8(engine)
{
setVTable(&static_vtbl);
- flags &= ~SimpleArray;
+ setArrayType(ArrayData::Custom);
}
QmlListWrapper::~QmlListWrapper()
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 36e0da5b60..625b3a3175 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -54,63 +54,6 @@
QT_BEGIN_NAMESPACE
-class QQmlLocaleData : public QV4::Object
-{
- Q_MANAGED
-public:
- QQmlLocaleData(QV4::ExecutionEngine *engine)
- : QV4::Object(engine)
- {
- setVTable(&static_vtbl);
- type = Type_Object;
- }
-
- QLocale locale;
-
- static QLocale *getThisLocale(QV4::CallContext *ctx) {
- QQmlLocaleData *thisObject = ctx->callData->thisObject.asObject()->as<QQmlLocaleData>();
- if (!thisObject) {
- ctx->throwTypeError();
- return 0;
- }
- return &thisObject->locale;
- }
-
- static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dateTimeFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_timeFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dateFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_monthName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_standaloneMonthName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dayName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_standaloneDayName(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_measurementSystem(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_textDirection(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_weekDays(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_uiLanguages(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_name(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_nativeLanguageName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_nativeCountryName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_decimalPoint(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_groupSeparator(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_percent(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_zeroDigit(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_negativeSign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_positiveSign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_exponential(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_amText(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx);
-
-private:
- static void destroy(Managed *that)
- {
- static_cast<QQmlLocaleData *>(that)->~QQmlLocaleData();
- }
-};
-
DEFINE_MANAGED_VTABLE(QQmlLocaleData);
#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
@@ -555,12 +498,12 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
result->arrayReserve(days.size());
- result->arrayDataLen = days.size();
+ result->arrayData->setLength(days.size());
for (int i = 0; i < days.size(); ++i) {
int day = days.at(i);
if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
day = 0;
- result->arrayData[i].value = QV4::Primitive::fromInt32(day);
+ result->arrayData->put(i, QV4::Primitive::fromInt32(day));
}
result->setArrayLengthUnchecked(days.size());
@@ -577,9 +520,10 @@ QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx)
QStringList langs = locale->uiLanguages();
QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
result->arrayReserve(langs.size());
+ QV4::ScopedValue v(scope);
for (int i = 0; i < langs.size(); ++i) {
- result->arrayData[i].value = ctx->engine->newString(langs.at(i));
- result->arrayDataLen = i + 1;
+ result->arrayData->put(i, (v = ctx->engine->newString(langs.at(i))));
+ result->arrayData->setLength(i + 1);
}
result->setArrayLengthUnchecked(langs.size());
@@ -857,14 +801,21 @@ QQmlLocale::~QQmlLocale()
{
}
-QV4::ReturnedValue QQmlLocale::locale(QV8Engine *v8engine, const QString &locale)
+QV4::ReturnedValue QQmlLocale::locale(QV8Engine *v8engine, const QString &localeName)
+{
+ QLocale qlocale;
+ if (!localeName.isEmpty())
+ qlocale = localeName;
+ return wrap(v8engine, qlocale);
+}
+
+QV4::ReturnedValue QQmlLocale::wrap(QV8Engine *engine, const QLocale &locale)
{
- QV8LocaleDataDeletable *d = localeV8Data(v8engine);
- QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine);
- QV4::Scope scope(engine);
- QV4::Scoped<QQmlLocaleData> wrapper(scope, new (engine->memoryManager) QQmlLocaleData(engine));
- if (!locale.isEmpty())
- wrapper->locale = QLocale(locale);
+ QV8LocaleDataDeletable *d = localeV8Data(engine);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope scope(v4);
+ QV4::Scoped<QQmlLocaleData> wrapper(scope, new (v4->memoryManager) QQmlLocaleData(v4));
+ wrapper->locale = locale;
QV4::ScopedObject p(scope, d->prototype.value());
wrapper->setPrototype(p.getPointer());
return wrapper.asReturnedValue();
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 8ca67a8c83..1f26f1834f 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -118,7 +118,8 @@ public:
Saturday = Qt::Saturday
};
- static QV4::ReturnedValue locale(QV8Engine *v8engine, const QString &lang);
+ static QV4::ReturnedValue locale(QV8Engine *v8engine, const QString &localeName);
+ static QV4::ReturnedValue wrap(QV8Engine *engine, const QLocale &locale);
static void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
@@ -128,6 +129,61 @@ private:
static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx);
};
+class QQmlLocaleData : public QV4::Object
+{
+ Q_MANAGED
+public:
+ QQmlLocaleData(QV4::ExecutionEngine *engine)
+ : QV4::Object(engine)
+ {
+ setVTable(&static_vtbl);
+ }
+
+ QLocale locale;
+
+ static QLocale *getThisLocale(QV4::CallContext *ctx) {
+ QQmlLocaleData *thisObject = ctx->callData->thisObject.asObject()->as<QQmlLocaleData>();
+ if (!thisObject) {
+ ctx->throwTypeError();
+ return 0;
+ }
+ return &thisObject->locale;
+ }
+
+ static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_dateTimeFormat(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_timeFormat(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_dateFormat(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_monthName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_standaloneMonthName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_dayName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_standaloneDayName(QV4::CallContext *ctx);
+
+ static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_measurementSystem(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_textDirection(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_weekDays(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_uiLanguages(QV4::CallContext *ctx);
+
+ static QV4::ReturnedValue method_get_name(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_nativeLanguageName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_nativeCountryName(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_decimalPoint(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_groupSeparator(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_percent(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_zeroDigit(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_negativeSign(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_positiveSign(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_exponential(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_amText(QV4::CallContext *ctx);
+ static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx);
+
+private:
+ static void destroy(Managed *that)
+ {
+ static_cast<QQmlLocaleData *>(that)->~QQmlLocaleData();
+ }
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index ed0c0afd6f..437e920d1a 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -664,7 +664,7 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
{
// Add any enum values defined by 'related' classes
if (metaObject->d.relatedMetaObjects) {
- const QMetaObject **related = metaObject->d.relatedMetaObjects;
+ const QMetaObject * const *related = metaObject->d.relatedMetaObjects;
if (related) {
while (*related)
insertEnums(*related++);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 3798129e8b..963b8272f4 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -42,7 +42,6 @@
#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>
@@ -52,9 +51,10 @@
#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>
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlpropertyvalueinterceptor_p.h>
QT_USE_NAMESPACE
@@ -70,394 +70,6 @@ struct ActiveOCRestorer
};
}
-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 = { /* runtimeFunctionIndex*/ 0, // ###
- int(s->nFormals),
- /* 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;
@@ -468,9 +80,10 @@ static void removeBindingOnProperty(QObject *o, int index)
}
QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData)
- : QQmlCompilePass(compiledData->url, compiledData->qmlUnit)
- , componentAttached(0)
+ : componentAttached(0)
+ , url(compiledData->url)
, engine(parentContext->engine)
+ , qmlUnit(compiledData->qmlUnit)
, jsUnit(compiledData->compilationUnit)
, parentContext(parentContext)
, context(0)
@@ -478,8 +91,9 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledD
, propertyCaches(compiledData->propertyCaches)
, vmeMetaObjectData(compiledData->datas)
, compiledData(compiledData)
+ , rootContext(0)
, _qobject(0)
- , _qobjectForBindings(0)
+ , _scopeObject(0)
, _valueTypeProperty(0)
, _compiledObject(0)
, _ddata(0)
@@ -512,6 +126,9 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->imports->addref();
context->setParent(parentContext);
+ if (!rootContext)
+ rootContext = context;
+
QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count());
for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
it != end; ++it) {
@@ -537,6 +154,10 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->importedScripts = parentContext->importedScripts;
}
+ QVector<QQmlParserStatus*> parserStatusCallbacks;
+ parserStatusCallbacks.resize(qmlUnit->nObjects);
+ qSwap(_parserStatusCallbacks, parserStatusCallbacks);
+
QObject *instance = createInstance(objectToCreate, parent);
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
@@ -546,6 +167,10 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->contextObject = instance;
}
+
+ qSwap(_parserStatusCallbacks, parserStatusCallbacks);
+ allParserStatusCallbacks.prepend(parserStatusCallbacks);
+
return instance;
}
@@ -558,7 +183,13 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope scope(v4);
- // ### enums
+
+ // ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
+ if (property->isEnum()) {
+ QVariant value = binding->valueAsString(&qmlUnit->header);
+ QQmlPropertyPrivate::write(_qobject, *property, value, context);
+ return;
+ }
switch (property->propType) {
case QMetaType::QVariant: {
@@ -1015,14 +646,32 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
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, /*value type property*/0))
+ if (!populateInstance(binding->value.objectIndex, qmlObject, cache, qmlObject, /*value type property*/0))
return false;
return true;
}
+ // ### resolve this at compile time
+ if (property && property->propType == qMetaTypeId<QQmlScriptString>()) {
+ QQmlScriptString ss(binding->valueAsScriptString(&qmlUnit->header), context->asQQmlContext(), _scopeObject);
+ ss.d.data()->bindingId = QQmlBinding::Invalid;
+ ss.d.data()->lineNumber = binding->location.line;
+ ss.d.data()->columnNumber = binding->location.column;
+ ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
+ ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
+ ss.d.data()->numberValue = binding->valueAsNumber();
+
+ QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ int propertyWriteStatus = -1;
+ void *argv[] = { &ss, 0, &propertyWriteStatus, &propertyWriteFlags };
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ return true;
+ }
+
QObject *createdSubObject = 0;
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- createdSubObject = createInstance(binding->value.objectIndex, _qobject);
+ createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
if (!createdSubObject)
return false;
}
@@ -1035,11 +684,11 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
- QQmlRefPointer<QQmlPropertyCache> groupedObjCache;
- QObject *groupedObjInstance = 0;
- QObject *objForBindings = _qobjectForBindings;
+ QQmlRefPointer<QQmlPropertyCache> groupObjectPropertyCache;
+ QObject *groupObject = 0;
QQmlValueType *valueType = 0;
QQmlPropertyData *valueTypeProperty = 0;
+ QObject *bindingTarget = _bindingTarget;
if (QQmlValueTypeFactory::isValueType(property->propType)) {
valueType = QQmlValueTypeFactory::valueType(property->propType);
@@ -1050,27 +699,27 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
valueType->read(_qobject, property->coreIndex);
- groupedObjCache = enginePrivate->cache(valueType);
- groupedObjInstance = valueType;
+ groupObjectPropertyCache = enginePrivate->cache(valueType);
+ groupObject = valueType;
valueTypeProperty = property;
} else {
- groupedObjCache = enginePrivate->propertyCacheForType(property->propType);
- if (!groupedObjCache) {
+ groupObjectPropertyCache = enginePrivate->propertyCacheForType(property->propType);
+ if (!groupObjectPropertyCache) {
recordError(binding->location, tr("Invalid grouped property access"));
return false;
}
- void *argv[1] = { &groupedObjInstance };
+ void *argv[1] = { &groupObject };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
- if (!groupedObjInstance) {
+ if (!groupObject) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
}
- objForBindings = groupedObjInstance;
+ bindingTarget = groupObject;
}
- if (!populateInstance(binding->value.objectIndex, groupedObjInstance, groupedObjCache, objForBindings, valueTypeProperty))
+ if (!populateInstance(binding->value.objectIndex, groupObject, groupObjectPropertyCache, bindingTarget, valueTypeProperty))
return false;
if (valueType)
@@ -1080,8 +729,9 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
}
}
- if (_ddata->hasBindingBit(property->coreIndex))
- removeBindingOnProperty(_qobject, property->coreIndex);
+ if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment))
+ removeBindingOnProperty(_bindingTarget, property->coreIndex);
if (binding->type == QV4::CompiledData::Binding::Type_Script) {
QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex];
@@ -1091,14 +741,14 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
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);
+ QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
+ QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
+ context, _scopeObject, function);
bs->takeExpression(expr);
} else {
- QQmlBinding *qmlBinding = new QQmlBinding(function, _qobject, context,
- QString(), 0, 0); // ###
+ QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context,
+ context->urlString, binding->location.line, binding->location.column);
// When writing bindings to grouped properties implemented as value types,
// such as point.x: { someExpression; }, then the binding is installed on
@@ -1109,7 +759,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
if (_valueTypeProperty)
targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
- qmlBinding->setTarget(_qobjectForBindings, targetCorePropertyData, context);
+ qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context);
qmlBinding->addToObject();
_createdBindings[bindingIndex] = qmlBinding;
@@ -1119,6 +769,43 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
}
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ // ### determine value source and interceptor casts ahead of time.
+ QQmlType *type = 0;
+ const QMetaObject *mo = createdSubObject->metaObject();
+ while (mo && !type) {
+ type = QQmlMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ Q_ASSERT(type);
+
+ QQmlPropertyData targetCorePropertyData = *property;
+ if (_valueTypeProperty)
+ targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
+
+ int valueSourceCast = type->propertyValueSourceCast();
+ if (valueSourceCast != -1) {
+ QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
+ QObject *target = createdSubObject->parent();
+ vs->setTarget(QQmlPropertyPrivate::restore(target, targetCorePropertyData, context));
+ return true;
+ }
+ int valueInterceptorCast = type->propertyValueInterceptorCast();
+ if (valueInterceptorCast != -1) {
+ QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast);
+ QObject *target = createdSubObject->parent();
+
+ QQmlProperty prop =
+ QQmlPropertyPrivate::restore(target, targetCorePropertyData, context);
+ vi->setTarget(prop);
+ QQmlVMEMetaObject *mo = QQmlVMEMetaObject::get(target);
+ Q_ASSERT(mo);
+ mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi);
+ return true;
+ }
+ return false;
+ }
+
QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
@@ -1203,7 +890,6 @@ void QmlObjectCreator::setupFunctions()
{
QV4::Scope scope(_qmlContext);
QV4::ScopedValue function(scope);
- QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(_qobject);
const quint32 *functionIdx = _compiledObject->functionOffsetTable();
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
@@ -1215,16 +901,27 @@ void QmlObjectCreator::setupFunctions()
continue;
function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction);
- vme->setVmeMethod(property->coreIndex, function);
+ _vmeMetaObject->setVmeMethod(property->coreIndex, function);
}
}
+void QmlObjectCreator::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;
+}
+
QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
{
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
bool isComponent = false;
QObject *instance = 0;
+ QQmlCustomParser *customParser = 0;
if (compiledData->isComponent(index)) {
isComponent = true;
@@ -1242,6 +939,16 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
+
+ const int parserStatusCast = type->parserStatusCast();
+ if (parserStatusCast != -1) {
+ QQmlParserStatus *parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
+ parserStatus->classBegin();
+ _parserStatusCallbacks[index] = parserStatus;
+ parserStatus->d = &_parserStatusCallbacks[index];
+ }
+
+ customParser = type->customParser();
} else {
Q_ASSERT(typeRef.component);
if (typeRef.component->qmlUnit->isSingleton())
@@ -1258,6 +965,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
if (subCreator.componentAttached)
subCreator.componentAttached->add(&componentAttached);
allCreatedBindings << subCreator.allCreatedBindings;
+ allParserStatusCallbacks << subCreator.allParserStatusCallbacks;
}
// ### use no-event variant
if (parent)
@@ -1285,18 +993,37 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
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, instance, /*value type property*/0))
- return 0;
+ if (customParser) {
+ QByteArray data = compiledData->customParserData.value(index);
+ customParser->setCustomData(instance, data);
}
- return instance;
+ if (isComponent)
+ return instance;
+
+ QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
+ Q_ASSERT(!cache.isNull());
+
+ QObject *scopeObject = instance;
+ qSwap(_scopeObject, scopeObject);
+
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope valueScope(v4);
+ QV4::ScopedObject jsScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
+ QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, jsScopeObject));
+ QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
+
+ qSwap(_qmlContext, qmlContext);
+
+ bool result = populateInstance(index, instance, cache, /*binding target*/instance, /*value type property*/0);
+
+ qSwap(_qmlContext, qmlContext);
+ qSwap(_scopeObject, scopeObject);
+
+ return result ? instance : 0;
}
-void QmlObjectCreator::finalize()
+QQmlContextData *QmlObjectCreator::finalize()
{
{
QQmlTrace trace("VME Binding Enable");
@@ -1321,6 +1048,45 @@ void QmlObjectCreator::finalize()
}
}
+ if (true /* ### componentCompleteEnabled()*/) { // the qml designer does the component complete later
+ QQmlTrace trace("VME Component Complete");
+ for (QLinkedList<QVector<QQmlParserStatus*> >::ConstIterator it = allParserStatusCallbacks.constBegin(), end = allParserStatusCallbacks.constEnd();
+ it != end; ++it) {
+ const QVector<QQmlParserStatus *> &parserStatusCallbacks = *it;
+ for (int i = parserStatusCallbacks.count() - 1; i >= 0; --i) {
+ QQmlParserStatus *status = parserStatusCallbacks.at(i);
+
+ if (status && status->d) {
+ status->d = 0;
+ status->componentComplete();
+ }
+
+ #if 0 // ###
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ return 0;
+ #endif
+ }
+ }
+ allParserStatusCallbacks.clear();
+ }
+
+ {
+ QQmlTrace trace("VME Finalize Callbacks");
+ for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
+ QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
+ QObject *obj = callback.first;
+ if (obj) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
+ }
+#if 0 // ###
+ if (watcher.hasRecursed())
+ return 0;
+#endif
+ }
+ finalizeCallbacks.clear();
+ }
+
{
QQmlTrace trace("VME Component.onCompleted Callbacks");
while (componentAttached) {
@@ -1339,35 +1105,34 @@ void QmlObjectCreator::finalize()
#endif
}
}
+
+ return rootContext;
}
-bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache,
- QObject *scopeObjectForBindings, QQmlPropertyData *valueTypeProperty)
+bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty)
{
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
- Q_ASSERT(scopeObjectForBindings);
-
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
qSwap(_propertyCache, cache);
qSwap(_qobject, instance);
- qSwap(_qobjectForBindings, scopeObjectForBindings);
qSwap(_valueTypeProperty, valueTypeProperty);
qSwap(_compiledObject, obj);
qSwap(_ddata, declarativeData);
+ qSwap(_bindingTarget, bindingTarget);
QQmlVMEMetaObject *vmeMetaObject = 0;
const QByteArray data = vmeMetaObjectData.value(index);
if (!data.isEmpty()) {
// install on _object
- vmeMetaObject = new QQmlVMEMetaObject(_qobjectForBindings, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
+ 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(_qobjectForBindings);
+ vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
}
_ddata->lineNumber = _compiledObject->location.line;
@@ -1378,387 +1143,21 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
qSwap(_createdBindings, createdBindings);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- QV4::Scope valueScope(v4);
- QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _qobjectForBindings));
- QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject));
- QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
-
- qSwap(_qmlContext, qmlContext);
-
setupBindings();
setupFunctions();
allCreatedBindings.append(_createdBindings);
- qSwap(_qmlContext, qmlContext);
-
qSwap(_createdBindings, createdBindings);
qSwap(_vmeMetaObject, vmeMetaObject);
- qSwap(_propertyCache, cache);
+ qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
qSwap(_compiledObject, obj);
qSwap(_valueTypeProperty, valueTypeProperty);
- qSwap(_qobjectForBindings, scopeObjectForBindings);
qSwap(_qobject, instance);
+ qSwap(_propertyCache, cache);
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 (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
- if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
- continue;
-
- QQmlCompiledData::TypeReference tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
- if (!tref.type)
- continue;
- if (tref.type->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 (quint32 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 (quint32 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) {
- recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
- return false;
- }
- 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) {
- recordError(p->aliasLocation, tr("Invalid alias location"));
- return false;
- }
-
- 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) {
- recordError(p->aliasLocation, tr("Invalid alias location"));
- return false;
- }
-
- propType = type;
-
- int valueTypeIndex =
- valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- recordError(p->aliasLocation, tr("Invalid alias location"));
- return false;
- }
- 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;
-}
-
-
-QQmlPropertyValidator::QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
- const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
- const QList<QQmlPropertyCache *> &propertyCaches, const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent)
- : QQmlCompilePass(url, qmlUnit)
- , resolvedTypes(resolvedTypes)
- , propertyCaches(propertyCaches)
- , objectIndexToIdPerComponent(objectIndexToIdPerComponent)
-{
-}
-
-bool QQmlPropertyValidator::validate()
-{
- for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
- if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
- continue;
-
- if (isComponent(i))
- continue;
-
- QQmlPropertyCache *propertyCache = propertyCaches.value(i);
- Q_ASSERT(propertyCache);
-
- if (!validateObject(obj, i, propertyCache))
- return false;
- }
- return true;
-}
-
-bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache)
-{
- PropertyResolver propertyResolver(propertyCache);
-
- QQmlPropertyData *defaultProperty = propertyCache->defaultProperty();
-
- const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
- || binding->type == QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- const QString name = stringAt(binding->propertyNameIndex);
-
- bool bindingToDefaultProperty = false;
-
- bool notInRevision = false;
- QQmlPropertyData *pd = 0;
- if (!name.isEmpty()) {
- pd = propertyResolver.property(name, &notInRevision);
-
- if (notInRevision) {
- QString typeName = stringAt(obj->inheritedTypeNameIndex);
- QQmlCompiledData::TypeReference type = resolvedTypes.value(objectIndex);
- if (type.type) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
- } else {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
- }
- }
- } else {
- pd = defaultProperty;
- bindingToDefaultProperty = true;
- }
-
- if (!pd) {
- if (bindingToDefaultProperty) {
- COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
- } else {
- COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
- }
- }
- }
-
- return true;
-}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index ec4b362491..a198396467 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -45,133 +45,60 @@
#include <private/qqmltypenamecache_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmlcompiler_p.h>
+#include <private/qqmltypecompiler_p.h>
#include <QLinkedList>
QT_BEGIN_NAMESPACE
class QQmlAbstractBinding;
+struct QQmlTypeCompiler;
-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();
-
- bool isComponentType(int typeNameIndex) const
- { return resolvedTypes.value(typeNameIndex).type == 0; }
-
- 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 QQmlPropertyValidator : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
-public:
- QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
- const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
- const QList<QQmlPropertyCache *> &propertyCaches,
- const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent);
-
- bool validate();
-
-private:
- bool validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache);
-
- bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
-
- const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes;
- const QList<QQmlPropertyCache *> &propertyCaches;
- const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
-};
-
-class QmlObjectCreator : public QQmlCompilePass
+class QmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
public:
QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData);
QObject *create(int subComponentIndex = -1, QObject *parent = 0);
- void finalize();
+ QQmlContextData *finalize();
QQmlComponentAttached *componentAttached;
QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
+ QList<QQmlError> errors;
+
private:
QObject *createInstance(int index, QObject *parent = 0);
- bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache,
- QObject *scopeObjectForJavaScript, QQmlPropertyData *valueTypeProperty);
+ bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty);
void setupBindings();
bool setPropertyValue(QQmlPropertyData *property, int index, const QV4::CompiledData::Binding *binding);
void setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
+ QString stringAt(int idx) const { return qmlUnit->header.stringAt(idx); }
+ void recordError(const QV4::CompiledData::Location &location, const QString &description);
+
+ QUrl url;
QQmlEngine *engine;
+ const QV4::CompiledData::QmlUnit *qmlUnit;
const QV4::CompiledData::CompilationUnit *jsUnit;
QQmlContextData *parentContext;
QQmlContextData *context;
const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
- const QList<QQmlPropertyCache *> propertyCaches;
- const QList<QByteArray> vmeMetaObjectData;
+ const QVector<QQmlPropertyCache *> propertyCaches;
+ const QVector<QByteArray> vmeMetaObjectData;
QHash<int, int> objectIndexToId;
QLinkedList<QVector<QQmlAbstractBinding*> > allCreatedBindings;
+ QLinkedList<QVector<QQmlParserStatus*> > allParserStatusCallbacks;
QQmlCompiledData *compiledData;
+ QQmlContextData *rootContext;
QObject *_qobject;
- QObject *_qobjectForBindings;
+ QObject *_scopeObject;
+ QObject *_bindingTarget;
+
QQmlPropertyData *_valueTypeProperty; // belongs to _qobjectForBindings's property cache
const QV4::CompiledData::Object *_compiledObject;
QQmlData *_ddata;
@@ -180,6 +107,7 @@ private:
QVector<QQmlAbstractBinding*> _createdBindings;
QQmlListProperty<void> _currentList;
QV4::ExecutionContext *_qmlContext;
+ QVector<QQmlParserStatus*> _parserStatusCallbacks;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlparserstatus.h b/src/qml/qml/qqmlparserstatus.h
index d3447e7752..1d63afd978 100644
--- a/src/qml/qml/qqmlparserstatus.h
+++ b/src/qml/qml/qqmlparserstatus.h
@@ -62,6 +62,7 @@ private:
friend class QQmlComponent;
friend class QQmlComponentPrivate;
friend class QQmlEnginePrivate;
+ friend class QmlObjectCreator;
QQmlParserStatus **d;
};
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 6c40557886..d026b95201 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1140,7 +1140,7 @@ QString QQmlPropertyCache::signalParameterStringForJS(QQmlEngine *engine, const
{
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
bool unnamedParameter = false;
- const QV4::IdentifierHash<bool> &illegalNames = ep->v8engine()->illegalNames();
+ const QSet<QString> &illegalNames = ep->v8engine()->illegalNames();
QString error;
QString parameters;
diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h
index 5421ef95fc..b192be8b77 100644
--- a/src/qml/qml/qqmlscriptstring.h
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE
class QObject;
class QQmlContext;
class QQmlScriptStringPrivate;
+class QmlObjectCreator;
class Q_QML_EXPORT QQmlScriptString
{
public:
@@ -74,6 +75,7 @@ private:
QQmlScriptString(const QString &script, QQmlContext *context, QObject *scope);
QSharedDataPointer<QQmlScriptStringPrivate> d;
+ friend class QmlObjectCreator;
friend class QQmlScriptStringPrivate;
friend class QQmlVME;
friend class QQmlExpression;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 6eda55e35b..278bb017d0 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -52,6 +52,7 @@
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmlcodegenerator_p.h>
+#include <private/qqmltypecompiler_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
@@ -2154,8 +2155,9 @@ void QQmlTypeData::dataReceived(const Data &data)
if (data.isFile()) preparseData = data.asFile()->metaData(QLatin1String("qml:preparse"));
if (m_useNewCompiler) {
- parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(typeLoader()->engine())->debugger != 0));
- QQmlCodeGenerator compiler;
+ QQmlEngine *qmlEngine = typeLoader()->engine();
+ parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(qmlEngine)->debugger != 0));
+ QQmlCodeGenerator compiler(QV8Engine::get(qmlEngine)->illegalNames());
if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) {
setError(compiler.errors);
return;
@@ -2305,173 +2307,9 @@ void QQmlTypeData::compile()
QQmlCompilingProfiler prof(m_compiledData->name);
if (m_useNewCompiler) {
- m_compiledData->importCache = new QQmlTypeNameCache;
-
- foreach (const QString &ns, m_namespaces)
- m_compiledData->importCache->add(ns);
-
- // Add any Composite Singletons that were used to the import cache
- for (int i = 0; i < compositeSingletons().count(); ++i) {
- m_compiledData->importCache->add(compositeSingletons().at(i).type->qmlTypeName(),
- compositeSingletons().at(i).type->sourceUrl(), compositeSingletons().at(i).prefix);
- }
-
- m_imports.populateCache(m_compiledData->importCache);
- m_compiledData->importCache->addref();
-
- QQmlEngine *engine = typeLoader()->engine();
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
-
- for (QHash<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);
- }
- ref.majorVersion = resolvedType->majorVersion;
- ref.minorVersion = resolvedType->minorVersion;
- 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;
- }
- }
-
- // Collect imported scripts
- m_compiledData->scripts.reserve(m_scripts.count());
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const ScriptReference &script = m_scripts.at(scriptIndex);
-
- QString qualifier = script.qualifier;
- QString enclosingNamespace;
-
- const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
- if (lastDotIndex != -1) {
- enclosingNamespace = qualifier.left(lastDotIndex);
- qualifier = qualifier.mid(lastDotIndex+1);
- }
-
- m_compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace);
- QQmlScriptData *scriptData = script.script->scriptData();
- scriptData->addref();
- m_compiledData->scripts << scriptData;
- }
-
- // Compile JS binding expressions and signal handlers
-
- JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
-
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
-
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
- isel->setUseFastLookups(false);
- QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
-
- // Generate QML compiled type data structures
-
- QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML.data(), runtimeFunctionIndices);
-
- if (jsUnit) {
- Q_ASSERT(!jsUnit->data);
- jsUnit->ownsData = false;
- jsUnit->data = &qmlUnit->header;
- }
-
- m_compiledData->compilationUnit = jsUnit;
- if (m_compiledData->compilationUnit)
- m_compiledData->compilationUnit->ref();
- m_compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData
-
- QList<QQmlError> errors;
-
- // Build property caches and VME meta object data
-
- m_compiledData->datas.reserve(qmlUnit->nObjects);
- m_compiledData->propertyCaches.reserve(qmlUnit->nObjects);
-
- QQmlPropertyCacheCreator propertyCacheBuilder(enginePrivate,
- 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();
- }
- }
-
- // Resolve component boundaries and aliases
-
- 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()) {
- // Add to type registry of composites
- if (m_compiledData->isCompositeType())
- QQmlEnginePrivate::get(engine)->registerInternalCompositeType(m_compiledData);
- else {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
- QQmlCompiledData::TypeReference typeRef = m_compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex);
- if (typeRef.component) {
- m_compiledData->metaTypeId = typeRef.component->metaTypeId;
- m_compiledData->listMetaTypeId = typeRef.component->listMetaTypeId;
- } else {
- m_compiledData->metaTypeId = typeRef.type->typeId();
- m_compiledData->listMetaTypeId = typeRef.type->qListTypeId();
- }
- }
- }
-
- // Sanity check property bindings
- if (errors.isEmpty()) {
- QQmlPropertyValidator validator(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes,
- m_compiledData->propertyCaches, m_compiledData->objectIndexToIdPerComponent);
- if (!validator.validate())
- errors << validator.errors;
- }
-
- if (!errors.isEmpty()) {
- setError(errors);
+ QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, parsedQML.data());
+ if (!compiler.compile()) {
+ setError(compiler.compilationErrors());
m_compiledData->release();
m_compiledData = 0;
}
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index b93cf2942d..a022162a7c 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -425,7 +425,12 @@ public:
const QQmlScript::Parser &parser() const;
+ // old compiler:
const QList<TypeReference> &resolvedTypes() const;
+ // new compiler:
+ const QHash<int, TypeReference> &resolvedTypeRefs() const { return m_resolvedTypes; }
+ // ---
+
const QList<ScriptReference> &resolvedScripts() const;
const QSet<QString> &namespaces() const;
const QList<TypeReference> &compositeSingletons() const;
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 33f5a00a6c..aa3b7eeb34 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -164,7 +164,7 @@ QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint)
QV4::ScopedArrayObject a(scope, value);
if (typeHint == qMetaTypeId<QList<QObject *> >()) {
QList<QObject *> list;
- uint32_t length = a->arrayLength();
+ uint32_t length = a->getLength();
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
for (uint32_t ii = 0; ii < length; ++ii) {
qobjectWrapper = a->getIndexed(ii);
@@ -196,9 +196,10 @@ static QV4::ReturnedValue arrayFromStringList(QV8Engine *engine, const QStringLi
QV4::Scoped<QV4::ArrayObject> a(scope, e->newArrayObject());
int len = list.count();
a->arrayReserve(len);
+ QV4::ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii) {
- a->arrayData[ii].value = QV4::Encode(e->newString(list.at(ii)));
- a->arrayDataLen = ii + 1;
+ a->arrayData->put(ii, (v = QV4::Encode(e->newString(list.at(ii)))));
+ a->arrayData->setLength(ii + 1);
}
a->setArrayLengthUnchecked(len);
return a.asReturnedValue();
@@ -211,9 +212,10 @@ static QV4::ReturnedValue arrayFromVariantList(QV8Engine *engine, const QVariant
QV4::Scoped<QV4::ArrayObject> a(scope, e->newArrayObject());
int len = list.count();
a->arrayReserve(len);
+ QV4::ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii) {
- a->arrayData[ii].value = engine->fromVariant(list.at(ii));
- a->arrayDataLen = ii + 1;
+ a->arrayData->put(ii, (v = engine->fromVariant(list.at(ii))));
+ a->arrayData->setLength(ii + 1);
}
a->setArrayLengthUnchecked(len);
return a.asReturnedValue();
@@ -298,7 +300,8 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
return QV4::JsonObject::fromJsonObject(m_v4Engine, *reinterpret_cast<const QJsonObject *>(ptr));
case QMetaType::QJsonArray:
return QV4::JsonObject::fromJsonArray(m_v4Engine, *reinterpret_cast<const QJsonArray *>(ptr));
-
+ case QMetaType::QLocale:
+ return QQmlLocale::wrap(this, *reinterpret_cast<const QLocale*>(ptr));
default:
break;
}
@@ -325,9 +328,10 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
const QList<QObject *> &list = *(QList<QObject *>*)ptr;
QV4::Scoped<QV4::ArrayObject> a(scope, m_v4Engine->newArrayObject());
a->arrayReserve(list.count());
+ QV4::ScopedValue v(scope);
for (int ii = 0; ii < list.count(); ++ii) {
- a->arrayData[ii].value = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii));
- a->arrayDataLen = ii + 1;
+ a->arrayData->put(ii, (v = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii))));
+ a->arrayData->setLength(ii + 1);
}
a->setArrayLengthUnchecked(list.count());
return a.asReturnedValue();
@@ -361,7 +365,7 @@ QNetworkAccessManager *QV8Engine::networkAccessManager()
return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager();
}
-const QV4::IdentifierHash<bool> &QV8Engine::illegalNames() const
+const QSet<QString> &QV8Engine::illegalNames() const
{
return m_illegalNames;
}
@@ -392,6 +396,8 @@ QVariant QV8Engine::toBasicVariant(const QV4::ValueRef value)
return value->asDouble();
if (value->isString())
return value->stringValue()->toQString();
+ if (QQmlLocaleData *ld = value->as<QQmlLocaleData>())
+ return ld->locale;
if (QV4::DateObject *d = value->asDateObject())
return d->toQDateTime();
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
@@ -407,7 +413,7 @@ QVariant QV8Engine::toBasicVariant(const QV4::ValueRef value)
QV4::ScopedValue v(scope);
QVariantList rv;
- int length = a->arrayLength();
+ int length = a->getLength();
for (int ii = 0; ii < length; ++ii) {
v = a->getIndexed(ii);
rv << toVariant(v, -1);
@@ -437,9 +443,8 @@ void QV8Engine::initializeGlobal()
qt_add_sqlexceptions(m_v4Engine);
{
- m_illegalNames = QV4::IdentifierHash<bool>(m_v4Engine);
for (uint i = 0; i < m_v4Engine->globalObject->internalClass->size; ++i)
- m_illegalNames.add(m_v4Engine->globalObject->internalClass->nameMap.at(i)->toQString(), true);
+ m_illegalNames.insert(m_v4Engine->globalObject->internalClass->nameMap.at(i)->toQString());
}
{
@@ -541,9 +546,10 @@ QV4::ReturnedValue QV8Engine::variantListToJS(const QVariantList &lst)
QV4::Scope scope(m_v4Engine);
QV4::Scoped<QV4::ArrayObject> a(scope, m_v4Engine->newArrayObject());
a->arrayReserve(lst.size());
+ QV4::ScopedValue v(scope);
for (int i = 0; i < lst.size(); i++) {
- a->arrayData[i].value = variantToJS(lst.at(i));
- a->arrayDataLen = i + 1;
+ a->arrayData->put(i, (v = variantToJS(lst.at(i))));
+ a->arrayData->setLength(i + 1);
}
a->setArrayLengthUnchecked(lst.size());
return a.asReturnedValue();
@@ -569,7 +575,7 @@ QVariantList QV8Engine::variantListFromJS(QV4::ArrayObjectRef a,
QV4::Scope scope(a->engine());
QV4::ScopedValue v(scope);
- quint32 length = a->arrayLength();
+ quint32 length = a->getLength();
for (quint32 i = 0; i < length; ++i) {
v = a->getIndexed(i);
result.append(variantFromJS(v, visitedObjects));
@@ -590,10 +596,11 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap)
QV4::Scoped<QV4::Object> o(scope, m_v4Engine->newObject());
QVariantMap::const_iterator it;
QV4::ScopedString s(scope);
+ QV4::ScopedValue v(scope);
for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) {
s = m_v4Engine->newIdentifier(it.key());
- QV4::Property *p = o->insertMember(s, QV4::Attr_Data);
- p->value = variantToJS(it.value());
+ v = variantToJS(it.value());
+ o->insertMember(s, v);
}
return o.asReturnedValue();
}
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index e37b0d4920..5d1005b479 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -217,7 +217,7 @@ public:
virtual QNetworkAccessManager *networkAccessManager();
// Return the list of illegal id names (the names of the properties on the global object)
- const QV4::IdentifierHash<bool> &illegalNames() const;
+ const QSet<QString> &illegalNames() const;
void gc();
@@ -268,7 +268,7 @@ protected:
QVector<Deletable *> m_extensionData;
Deletable *m_listModelData;
- QV4::IdentifierHash<bool> m_illegalNames;
+ QSet<QString> m_illegalNames;
QElapsedTimer m_time;
QHash<QString, qint64> m_startedTimers;
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 5e6a1a084a..b8920deb21 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -251,6 +251,44 @@ QQmlConnectionsParser::compile(const QList<QQmlCustomParserProperty> &props)
return rv;
}
+QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+{
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ for (int ii = 0; ii < props.count(); ++ii) {
+ const QV4::CompiledData::Binding *binding = props.at(ii);
+ QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
+ int propLine = binding->location.line;
+ int propColumn = binding->location.column;
+
+ if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
+ error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
+ return QByteArray();
+ }
+
+
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
+ if (!qmlUnit->header.stringAt(target->inheritedTypeNameIndex).isEmpty())
+ error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
+ else
+ error(binding, QQmlConnections::tr("Connections: syntax error"));
+ return QByteArray();
+ } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
+ error(binding, QQmlConnections::tr("Connections: script expected"));
+ return QByteArray();
+ } else {
+ ds << propName;
+ ds << binding->valueAsString(&qmlUnit->header);
+ ds << propLine;
+ ds << propColumn;
+ }
+ }
+
+ return rv;
+}
+
void QQmlConnectionsParser::setCustomData(QObject *object,
const QByteArray &data)
{
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index 9bc668e5f4..2579e4c239 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -85,6 +85,7 @@ class QQmlConnectionsParser : public QQmlCustomParser
{
public:
virtual QByteArray compile(const QList<QQmlCustomParserProperty> &);
+ virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
virtual void setCustomData(QObject *, const QByteArray &);
};
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 7276c0e5c6..4c8635b29c 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1629,37 +1629,46 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
proto->defineAccessorProperty(QStringLiteral("model"), QQmlDelegateModelItem::get_model, 0);
proto->defineAccessorProperty(QStringLiteral("groups"), QQmlDelegateModelItem::get_groups, QQmlDelegateModelItem::set_groups);
QV4::ScopedString s(scope);
+ QV4::Property p;
+
s = v4->newString(QStringLiteral("isUnresolved"));
- QV4::Property *p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, 30, QQmlDelegateModelItem::get_member));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, 30, QQmlDelegateModelItem::get_member));
+ p.setSetter(0);
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+
s = v4->newString(QStringLiteral("inItems"));
- p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member));
- p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member));
+ p.setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member));
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+
s = v4->newString(QStringLiteral("inPersistedItems"));
- p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member));
- p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member));
+ p.setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member));
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+
s = v4->newString(QStringLiteral("itemsIndex"));
- p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index));
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+
s = v4->newString(QStringLiteral("persistedItemsIndex"));
- p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index));
+ p.setSetter(0);
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
for (int i = 2; i < groupNames.count(); ++i) {
QString propertyName = QStringLiteral("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4->newString(propertyName);
- p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member));
- p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member));
+ p.setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member));
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.count(); ++i) {
const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
s = v4->newString(propertyName);
- p = proto->insertMember(s, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index));
+ p.setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index));
+ p.setSetter(0);
+ proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
modelItemProto = proto;
}
@@ -1692,7 +1701,7 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::ValueRef groups) const
QV4::ScopedArrayObject array(scope, groups);
if (array) {
QV4::ScopedValue v(scope);
- uint arrayLength = array->arrayLength();
+ uint arrayLength = array->getLength();
for (uint i = 0; i < arrayLength; ++i) {
v = array->getIndexed(i);
const QString groupName = v->toQString();
@@ -1863,11 +1872,16 @@ void QQmlDelegateModelItem::incubateObject(
incubatorPriv->compiledData = componentPriv->cc;
incubatorPriv->compiledData->addref();
- incubatorPriv->vme.init(
- context,
- componentPriv->cc,
- componentPriv->start,
- componentPriv->creationContext);
+ if (enginePriv->useNewCompiler) {
+ incubatorPriv->creator.reset(new QmlObjectCreator(context, componentPriv->cc));
+ incubatorPriv->subComponentToCreate = componentPriv->start;
+ } else {
+ incubatorPriv->vme.init(
+ context,
+ componentPriv->cc,
+ componentPriv->start,
+ componentPriv->creationContext);
+ }
enginePriv->incubate(*incubationTask, forContext);
}
@@ -3184,7 +3198,7 @@ public:
: Object(engine)
{
setVTable(&static_vtbl);
- flags &= ~SimpleArray;
+ setArrayType(QV4::ArrayData::Custom);
}
virtual ~QQmlDelegateModelGroupChangeArray() {}
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 7e441023c9..eeb4aa0861 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -441,7 +441,7 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
ListModel *subModel = new ListModel(r.subLayout, 0, -1);
- int arrayLength = a->arrayLength();
+ int arrayLength = a->getLength();
for (int j=0 ; j < arrayLength ; ++j) {
o = a->getIndexed(j);
subModel->append(o, eng);
@@ -517,7 +517,7 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng)
if (r.type == ListLayout::Role::List) {
ListModel *subModel = new ListModel(r.subLayout, 0, -1);
- int arrayLength = a->arrayLength();
+ int arrayLength = a->getLength();
for (int j=0 ; j < arrayLength ; ++j) {
o = a->getIndexed(j);
subModel->append(o, eng);
@@ -1188,7 +1188,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::ValueRef
QV4::Scoped<QV4::Object> o(scope);
ListModel *subModel = new ListModel(role.subLayout, 0, -1);
- int arrayLength = a->arrayLength();
+ int arrayLength = a->getLength();
for (int j=0 ; j < arrayLength ; ++j) {
o = a->getIndexed(j);
subModel->append(o, eng);
@@ -1953,7 +1953,7 @@ void QQmlListModel::insert(QQmlV4Function *args)
if (objectArray) {
QV4::ScopedObject argObject(scope);
- int objectArrayLength = objectArray->arrayLength();
+ int objectArrayLength = objectArray->getLength();
for (int i=0 ; i < objectArrayLength ; ++i) {
argObject = objectArray->getIndexed(i);
@@ -2055,7 +2055,7 @@ void QQmlListModel::append(QQmlV4Function *args)
if (objectArray) {
QV4::Scoped<QV4::Object> argObject(scope);
- int objectArrayLength = objectArray->arrayLength();
+ int objectArrayLength = objectArray->getLength();
int index = count();
for (int i=0 ; i < objectArrayLength ; ++i) {
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 722cb2b44d..a7487537c5 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -188,8 +188,12 @@ private:
ListModel *model;
int elementIndex;
};
+
+ friend class QTypeInfo<QQmlListModelParser::ListInstruction>;
};
+Q_DECLARE_TYPEINFO(QQmlListModelParser::ListInstruction, Q_PRIMITIVE_TYPE);
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlListModel)
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 38fdffdde6..36c3623d8b 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -226,9 +226,10 @@ public:
const QByteArray &propertyName = it.key();
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::Property *p = proto->insertMember(name, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
- p->setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property));
- p->setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property));
+ QV4::Property p;
+ p.setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property));
+ p.setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property));
+ proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
}
prototype = proto;
}