aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h2
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qanimationjobutil_p.h2
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qpauseanimationjob_p.h2
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h2
-rw-r--r--src/qml/configure.json47
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h6
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp9
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/jsapi/qjsengine.cpp8
-rw-r--r--src/qml/jsruntime/jsruntime.pri10
-rw-r--r--src/qml/jsruntime/qv4engine.cpp35
-rw-r--r--src/qml/jsruntime/qv4engine_p.h12
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp314
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h33
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp9
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp10
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp18
-rw-r--r--src/qml/memory/qv4heap_p.h78
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp7
-rw-r--r--src/qml/parser/qqmljslexer.cpp433
-rw-r--r--src/qml/parser/qqmljslexer_p.h14
-rw-r--r--src/qml/qml.pro2
-rw-r--r--src/qml/qml/qml.pri21
-rw-r--r--src/qml/qml/qqmlengine.cpp15
-rw-r--r--src/qml/qml/qqmllocale_p.h2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h4
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp6
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h2
-rw-r--r--src/qml/qml/v8/qv8engine.cpp20
-rw-r--r--src/qml/qml/v8/qv8engine_p.h9
-rw-r--r--src/qml/qtqmlglobal.h1
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp129
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h12
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h5
-rw-r--r--src/qml/types/qqmllistmodel_p.h2
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h2
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h2
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp5
-rw-r--r--src/qml/types/qqmltimer_p.h2
-rw-r--r--src/qml/types/qquickworkerscript.cpp5
-rw-r--r--src/qml/types/types.pri18
-rw-r--r--src/qml/util/qqmladaptormodel.cpp100
-rw-r--r--src/qml/util/qqmladaptormodel_p.h12
48 files changed, 968 insertions, 471 deletions
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 63fd4b0dac..0be6ca96ea 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -56,6 +56,8 @@
#include <QtCore/private/qabstractanimation_p.h>
#include <vector>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class QAnimationGroupJob;
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index fb567dc019..b01b2f3b36 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -54,6 +54,8 @@
#include "private/qabstractanimationjob_p.h"
#include <QtCore/qdebug.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h
index 0bb9e83b2d..e3d6fe9178 100644
--- a/src/qml/animations/qanimationjobutil_p.h
+++ b/src/qml/animations/qanimationjobutil_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
+QT_REQUIRE_CONFIG(qml_animation);
+
#define RETURN_IF_DELETED(func) \
{ \
bool *prevWasDeleted = m_wasDeleted; \
diff --git a/src/qml/animations/qcontinuinganimationgroupjob_p.h b/src/qml/animations/qcontinuinganimationgroupjob_p.h
index baf4ff1ae5..c67b8d39ad 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob_p.h
+++ b/src/qml/animations/qcontinuinganimationgroupjob_p.h
@@ -53,6 +53,8 @@
#include "private/qanimationgroupjob_p.h"
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QContinuingAnimationGroupJob : public QAnimationGroupJob
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
index 67ba626247..0265fe3274 100644
--- a/src/qml/animations/qparallelanimationgroupjob_p.h
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -53,6 +53,8 @@
#include "private/qanimationgroupjob_p.h"
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QParallelAnimationGroupJob : public QAnimationGroupJob
diff --git a/src/qml/animations/qpauseanimationjob_p.h b/src/qml/animations/qpauseanimationjob_p.h
index d0e8d57fc7..6c9bbf0dab 100644
--- a/src/qml/animations/qpauseanimationjob_p.h
+++ b/src/qml/animations/qpauseanimationjob_p.h
@@ -53,6 +53,8 @@
#include <private/qanimationgroupjob_p.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QPauseAnimationJob : public QAbstractAnimationJob
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
index 800f0c3b90..13f9806be1 100644
--- a/src/qml/animations/qsequentialanimationgroupjob_p.h
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -53,6 +53,8 @@
#include <private/qanimationgroupjob_p.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class QPauseAnimationJob;
diff --git a/src/qml/configure.json b/src/qml/configure.json
index b744ea6948..47b897ce27 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -39,6 +39,47 @@
"features.xmlstreamwriter"
],
"output": [ "privateFeature" ]
+ },
+ "qml-devtools": {
+ "label": "QML Development Tools",
+ "purpose": "Provides the QmlDevtools library and various utilities.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-sequence-object": {
+ "label": "QML sequence object",
+ "purpose": "Supports mapping sequence types into QML.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-list-model": {
+ "label": "QML list model",
+ "purpose": "Provides the ListModel QML type.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-xml-http-request": {
+ "label": "QML XML http request",
+ "purpose": "Provides support for sending XML http requests.",
+ "section": "QML",
+ "condition": [
+ "features.xmlstreamreader",
+ "features.qml-network"
+ ],
+ "output": [ "privateFeature" ]
+ },
+ "qml-locale": {
+ "label": "QML Locale",
+ "purpose": "Provides support for locales in QML.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-animation": {
+ "label": "QML Animations",
+ "purpose": "Provides support for animations and timers in QML.",
+ "section": "QML",
+ "condition": "features.animation",
+ "output": [ "privateFeature" ]
}
},
@@ -47,7 +88,11 @@
"section": "Qt QML",
"entries": [
"qml-network",
- "qml-debug"
+ "qml-debug",
+ "qml-sequence-object",
+ "qml-list-model",
+ "qml-xml-http-request",
+ "qml-locale"
]
}
]
diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h
index c63e694c7e..f39f8fccd2 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter_p.h
+++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h
@@ -73,13 +73,13 @@ public:
~QQmlAbstractProfilerAdapter() override {}
void setService(QQmlProfilerService *new_service) { service = new_service; }
- virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) = 0;
+ virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) = 0;
void startProfiling(quint64 features);
void stopProfiling();
- void reportData(bool trackLocations) { emit dataRequested(trackLocations); }
+ void reportData() { emit dataRequested(); }
void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; }
@@ -96,7 +96,7 @@ signals:
void profilingDisabled();
void profilingDisabledWhileWaiting();
- void dataRequested(bool trackLocations);
+ void dataRequested();
void referenceTimeKnown(const QElapsedTimer &timer);
protected:
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index 8c0bd73822..da0b14dd85 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -59,19 +59,18 @@ void QQmlProfiler::startProfiling(quint64 features)
void QQmlProfiler::stopProfiling()
{
featuresEnabled = false;
- reportData(true);
+ reportData();
m_locations.clear();
}
-void QQmlProfiler::reportData(bool trackLocations)
+void QQmlProfiler::reportData()
{
LocationHash resolved;
resolved.reserve(m_locations.size());
for (auto it = m_locations.begin(), end = m_locations.end(); it != end; ++it) {
- if (!trackLocations || !it->sent) {
+ if (!it->sent) {
resolved.insert(it.key(), it.value());
- if (trackLocations)
- it->sent = true;
+ it->sent = true;
}
}
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index deb4d107d6..44d208db41 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -383,7 +383,7 @@ public:
void startProfiling(quint64 features);
void stopProfiling();
- void reportData(bool trackLocations);
+ void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index c483af638b..924de14bc7 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -304,9 +304,9 @@ QJSEngine::QJSEngine()
QJSEngine::QJSEngine(QObject *parent)
: QObject(*new QJSEnginePrivate, parent)
- , m_v4Engine(new QV4::ExecutionEngine)
+ , m_v4Engine(new QV4::ExecutionEngine(this))
{
- m_v4Engine->v8Engine = new QV8Engine(this, m_v4Engine);
+ m_v4Engine->v8Engine = new QV8Engine(m_v4Engine);
checkForApplicationInstance();
QJSEnginePrivate::addToDebugServer(this);
@@ -317,9 +317,9 @@ QJSEngine::QJSEngine(QObject *parent)
*/
QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
: QObject(dd, parent)
- , m_v4Engine(new QV4::ExecutionEngine)
+ , m_v4Engine(new QV4::ExecutionEngine(this))
{
- m_v4Engine->v8Engine = new QV8Engine(this, m_v4Engine);
+ m_v4Engine->v8Engine = new QV8Engine(m_v4Engine);
checkForApplicationInstance();
}
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 4bc877bd9d..1ec00cc744 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -36,7 +36,6 @@ SOURCES += \
$$PWD/qv4runtimecodegen.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
- $$PWD/qv4sequenceobject.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4arraybuffer.cpp \
@@ -89,7 +88,6 @@ HEADERS += \
$$PWD/qv4script_p.h \
$$PWD/qv4scopedvalue_p.h \
$$PWD/qv4executableallocator_p.h \
- $$PWD/qv4sequenceobject_p.h \
$$PWD/qv4include_p.h \
$$PWD/qv4qobjectwrapper_p.h \
$$PWD/qv4profiling_p.h \
@@ -98,6 +96,14 @@ HEADERS += \
$$PWD/qv4dataview_p.h \
$$PWD/qv4vme_moth_p.h
+qtConfig(qml-sequence-object) {
+ HEADERS += \
+ $$PWD/qv4sequenceobject_p.h
+
+ SOURCES += \
+ $$PWD/qv4sequenceobject.cpp
+}
+
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 5f59e1e809..b697a2081b 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -63,7 +63,11 @@
#include "qv4debugging_p.h"
#include "qv4profiling_p.h"
#include "qv4executableallocator_p.h"
+
+#if QT_CONFIG(qml_sequence_object)
#include "qv4sequenceobject_p.h"
+#endif
+
#include "qv4qobjectwrapper_p.h"
#include "qv4memberdata_p.h"
#include "qv4arraybuffer_p.h"
@@ -76,7 +80,9 @@
#include <private/qqmlvaluetype_p.h>
#include <private/qqmllistwrapper_p.h>
#include <private/qqmllist_p.h>
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <QtCore/QTextStream>
#include <QDateTime>
@@ -110,7 +116,7 @@ ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const
#ifdef V4_BOOTSTRAP
QJSEngine *ExecutionEngine::jsEngine() const
{
- return v8Engine->publicEngine();
+ return publicEngine;
}
QQmlEngine *ExecutionEngine::qmlEngine() const
@@ -121,7 +127,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const
qint32 ExecutionEngine::maxCallDepth = -1;
-ExecutionEngine::ExecutionEngine()
+ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
: executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
@@ -129,6 +135,7 @@ ExecutionEngine::ExecutionEngine()
, gcStack(new WTF::PageAllocation)
, globalCode(nullptr)
, v8Engine(nullptr)
+ , publicEngine(jsEngine)
, argumentsAccessors(nullptr)
, nArgumentsAccessors(0)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
@@ -346,8 +353,10 @@ ExecutionEngine::ExecutionEngine()
jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>();
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
+#if QT_CONFIG(qml_sequence_object)
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic, SequencePrototype::defaultPrototype(this)));
+#endif
ExecutionContext *global = rootContext();
jsObjects[Object_Ctor] = memoryManager->allocObject<ObjectCtor>(global);
@@ -382,10 +391,11 @@ ExecutionEngine::ExecutionEngine()
static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor());
static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
-
static_cast<VariantPrototype *>(variantPrototype())->init();
- sequencePrototype()->cast<SequencePrototype>()->init();
+#if QT_CONFIG(qml_sequence_object)
+ sequencePrototype()->cast<SequencePrototype>()->init();
+#endif
// typed arrays
@@ -524,7 +534,7 @@ void ExecutionEngine::initRootContext()
jsObjects[IntegerNull] = Encode((int)0);
}
-InternalClass *ExecutionEngine::newClass(const InternalClass &other)
+InternalClass *ExecutionEngine::newClass(InternalClass *other)
{
return new (classPool) InternalClass(other);
}
@@ -1141,8 +1151,11 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return v->toVariant();
} else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
return l->toVariant();
- } else if (object->isListType())
+#if QT_CONFIG(qml_sequence_object)
+ } else if (object->isListType()) {
return QV4::SequencePrototype::toVariant(object);
+#endif
+ }
}
if (value.as<ArrayObject>()) {
@@ -1165,10 +1178,12 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
}
+#if QT_CONFIG(qml_sequence_object)
bool succeeded = false;
QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
if (succeeded)
return retn;
+#endif
}
if (value.isUndefined())
@@ -1188,8 +1203,10 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return str.at(0);
return str;
}
+#if QT_CONFIG(qml_locale)
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
return *ld->d()->locale;
+#endif
if (const QV4::DateObject *d = value.as<DateObject>())
return d->toQDateTime();
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
@@ -1345,6 +1362,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
+#if QT_CONFIG(qml_sequence_object)
case QMetaType::QStringList:
{
bool succeeded = false;
@@ -1354,6 +1372,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return retn->asReturnedValue();
return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
}
+#endif
case QMetaType::QVariantList:
return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
case QMetaType::QVariantMap:
@@ -1364,8 +1383,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(ptr));
case QMetaType::QJsonArray:
return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(ptr));
+#if QT_CONFIG(qml_locale)
case QMetaType::QLocale:
return QQmlLocale::wrap(this, *reinterpret_cast<const QLocale*>(ptr));
+#endif
default:
break;
}
@@ -1405,10 +1426,12 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
if (objOk)
return QV4::QObjectWrapper::wrap(this, obj);
+#if QT_CONFIG(qml_sequence_object)
bool succeeded = false;
QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
if (succeeded)
return retn->asReturnedValue();
+#endif
if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 5edf89f720..d21b623a1e 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -88,7 +88,6 @@ struct CompilationUnit;
}
struct Function;
-struct InternalClass;
struct InternalClassPool;
struct Q_QML_EXPORT CppStackFrame {
@@ -153,10 +152,11 @@ public:
QJSEngine *jsEngine() const;
QQmlEngine *qmlEngine() const;
#else // !V4_BOOTSTRAP
- QJSEngine *jsEngine() const { return v8Engine->publicEngine(); }
+ QJSEngine *jsEngine() const { return publicEngine; }
QQmlEngine *qmlEngine() const { return v8Engine ? v8Engine->engine() : nullptr; }
#endif // V4_BOOTSTRAP
QV8Engine *v8Engine;
+ QJSEngine *publicEngine;
enum JSObjects {
RootContext,
@@ -178,7 +178,9 @@ public:
TypeErrorProto,
URIErrorProto,
VariantProto,
+#if QT_CONFIG(qml_sequence_object)
SequenceProto,
+#endif
ArrayBufferProto,
DataViewProto,
ValueTypeProto,
@@ -247,7 +249,9 @@ public:
Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); }
Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
+#if QT_CONFIG(qml_sequence_object)
Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
+#endif
Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); }
@@ -374,7 +378,7 @@ public:
int internalClassIdCount = 0;
- ExecutionEngine();
+ ExecutionEngine(QJSEngine *jsEngine = nullptr);
~ExecutionEngine();
#if !QT_CONFIG(qml_debug)
@@ -454,7 +458,7 @@ public:
void initRootContext();
- InternalClass *newClass(const InternalClass &other);
+ InternalClass *newClass(InternalClass *other);
StackTrace exceptionStackTrace;
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 9da854e7d7..69ca62cb5c 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -74,24 +74,8 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
// fill up to max 50%
bool grow = (d->alloc <= d->size*2);
- if (classSize < d->size || grow) {
- PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
- for (int i = 0; i < d->alloc; ++i) {
- const Entry &e = d->entries[i];
- if (!e.identifier || e.index >= static_cast<unsigned>(classSize))
- continue;
- uint idx = e.identifier->hashValue % dd->alloc;
- while (dd->entries[idx].identifier) {
- ++idx;
- idx %= dd->alloc;
- }
- dd->entries[idx] = e;
- }
- dd->size = classSize;
- Q_ASSERT(d->refCount > 1);
- --d->refCount;
- d = dd;
- }
+ if (classSize < d->size || grow)
+ detach(grow, classSize);
uint idx = entry.identifier->hashValue % d->alloc;
while (d->entries[idx].identifier) {
@@ -102,11 +86,52 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
+int PropertyHash::removeIdentifier(Identifier *identifier, int classSize)
+{
+ detach(false, classSize);
+ uint idx = identifier->hashValue % d->alloc;
+ while (1) {
+ if (d->entries[idx].identifier == identifier) {
+ int val = d->entries[idx].index;
+ d->entries[idx] = { nullptr, 0 };
+ return val;
+ }
+
+ ++idx;
+ idx %= d->alloc;
+ }
+ Q_UNREACHABLE();
+}
+
+void PropertyHash::detach(bool grow, int classSize)
+{
+ if (d->refCount == 1 && !grow)
+ return;
+
+ PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
+ for (int i = 0; i < d->alloc; ++i) {
+ const Entry &e = d->entries[i];
+ if (!e.identifier || e.index >= static_cast<unsigned>(classSize))
+ continue;
+ uint idx = e.identifier->hashValue % dd->alloc;
+ while (dd->entries[idx].identifier) {
+ ++idx;
+ idx %= dd->alloc;
+ }
+ dd->entries[idx] = e;
+ }
+ dd->size = classSize;
+ if (!--d->refCount)
+ delete d;
+ d = dd;
+}
+
InternalClass::InternalClass(ExecutionEngine *engine)
: engine(engine)
, vtable(nullptr)
, prototype(nullptr)
+ , parent(nullptr)
, m_sealed(nullptr)
, m_frozen(nullptr)
, size(0)
@@ -116,19 +141,20 @@ InternalClass::InternalClass(ExecutionEngine *engine)
}
-InternalClass::InternalClass(const QV4::InternalClass &other)
+InternalClass::InternalClass(QV4::InternalClass *other)
: QQmlJS::Managed()
- , engine(other.engine)
- , vtable(other.vtable)
- , prototype(other.prototype)
- , propertyTable(other.propertyTable)
- , nameMap(other.nameMap)
- , propertyData(other.propertyData)
+ , engine(other->engine)
+ , vtable(other->vtable)
+ , prototype(other->prototype)
+ , parent(other)
+ , propertyTable(other->propertyTable)
+ , nameMap(other->nameMap)
+ , propertyData(other->propertyData)
, m_sealed(nullptr)
, m_frozen(nullptr)
- , size(other.size)
- , extensible(other.extensible)
- , isUsedAsProto(other.isUsedAsProto)
+ , size(other->size)
+ , extensible(other->extensible)
+ , isUsedAsProto(other->isUsedAsProto)
{
id = engine->newInternalClassId();
}
@@ -183,6 +209,15 @@ InternalClassTransition &InternalClass::lookupOrInsertTransition(const InternalC
}
}
+static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
+{
+ // add a dummy entry, since we need two entries for accessors
+ newClass->propertyTable.addEntry(e, newClass->size);
+ newClass->nameMap.add(newClass->size, nullptr);
+ newClass->propertyData.add(newClass->size, PropertyAttributes());
+ ++newClass->size;
+}
+
InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttributes data, uint *index)
{
data.resolve();
@@ -201,14 +236,34 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
- newClass = newClass->changePrototype(prototype);
- for (uint i = 0; i < size; ++i) {
- if (i == idx) {
- newClass = newClass->addMember(nameMap.at(i), data);
- } else if (!propertyData.at(i).isEmpty()) {
- newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
+ InternalClass *newClass = engine->newClass(this);
+ if (data.isAccessor() != propertyData.at(idx).isAccessor()) {
+ // this changes the layout of the class, so we need to rebuild the data
+ newClass->propertyTable = PropertyHash();
+ newClass->nameMap = SharedInternalClassData<Identifier *>();
+ newClass->propertyData = SharedInternalClassData<PropertyAttributes>();
+ newClass->size = 0;
+ for (uint i = 0; i < size; ++i) {
+ Identifier *identifier = nameMap.at(i);
+ PropertyHash::Entry e = { identifier, newClass->size };
+ if (!identifier)
+ e.identifier = nameMap.at(i - 1);
+ newClass->propertyTable.addEntry(e, newClass->size);
+ newClass->nameMap.add(newClass->size, identifier);
+ if (i == idx) {
+ newClass->propertyData.add(newClass->size, data);
+ ++newClass->size;
+ if (data.isAccessor())
+ addDummyEntry(newClass, e);
+ else
+ ++i;
+ } else {
+ newClass->propertyData.add(newClass->size, propertyData.at(i));
+ ++newClass->size;
+ }
}
+ } else {
+ newClass->propertyData.set(idx, data);
}
t.lookup = newClass;
@@ -231,18 +286,8 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass;
- if (!size && !prototype) {
- newClass = engine->newClass(*this);
- newClass->prototype = proto;
- } else {
- newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
- newClass = newClass->changePrototype(proto);
- for (uint i = 0; i < size; ++i) {
- if (!propertyData.at(i).isEmpty())
- newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
- }
- }
+ InternalClass *newClass = engine->newClass(this);
+ newClass->prototype = proto;
t.lookup = newClass;
@@ -261,18 +306,8 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass;
- if (this == engine->internalClasses[EngineBase::Class_Empty]) {
- newClass = engine->newClass(*this);
- newClass->vtable = vt;
- } else {
- newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vt);
- newClass = newClass->changePrototype(prototype);
- for (uint i = 0; i < size; ++i) {
- if (!propertyData.at(i).isEmpty())
- newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
- }
- }
+ InternalClass *newClass = engine->newClass(this);
+ newClass->vtable = vt;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -290,7 +325,7 @@ InternalClass *InternalClass::nonExtensible()
if (t.lookup)
return t.lookup;
- InternalClass *newClass = engine->newClass(*this);
+ InternalClass *newClass = engine->newClass(this);
newClass->extensible = false;
t.lookup = newClass;
@@ -343,20 +378,15 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass = engine->newClass(*this);
+ InternalClass *newClass = engine->newClass(this);
PropertyHash::Entry e = { identifier, newClass->size };
newClass->propertyTable.addEntry(e, newClass->size);
newClass->nameMap.add(newClass->size, identifier);
newClass->propertyData.add(newClass->size, data);
++newClass->size;
- if (data.isAccessor()) {
- // add a dummy entry, since we need two entries for accessors
- newClass->propertyTable.addEntry(e, newClass->size);
- newClass->nameMap.add(newClass->size, 0);
- newClass->propertyData.add(newClass->size, PropertyAttributes());
- ++newClass->size;
- }
+ if (data.isAccessor())
+ addDummyEntry(newClass, e);
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -366,36 +396,25 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr
void InternalClass::removeMember(Object *object, Identifier *id)
{
InternalClass *oldClass = object->internalClass();
- uint propIdx = oldClass->propertyTable.lookup(id);
- Q_ASSERT(propIdx < oldClass->size);
+ Q_ASSERT(oldClass->propertyTable.lookup(id) < oldClass->size);
- Transition temp = { { id }, nullptr, -1 };
+ Transition temp = { { id }, nullptr, Transition::RemoveMember };
Transition &t = object->internalClass()->lookupOrInsertTransition(temp);
- bool accessor = oldClass->propertyData.at(propIdx).isAccessor();
-
- if (t.lookup) {
- object->setInternalClass(t.lookup);
- } else {
+ if (!t.lookup) {
// create a new class and add it to the tree
- InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable);
- newClass = newClass->changePrototype(oldClass->prototype);
- for (uint i = 0; i < oldClass->size; ++i) {
- if (i == propIdx)
- continue;
- if (!oldClass->propertyData.at(i).isEmpty())
- newClass = newClass->addMember(oldClass->nameMap.at(i), oldClass->propertyData.at(i));
- }
- object->setInternalClass(newClass);
+ InternalClass *newClass = oldClass->engine->newClass(oldClass);
+ // simply make the entry inaccessible
+ int idx = newClass->propertyTable.removeIdentifier(id, oldClass->size);
+ newClass->nameMap.set(idx, nullptr);
+ newClass->propertyData.set(idx, PropertyAttributes());
+ t.lookup = newClass;
+ Q_ASSERT(t.lookup);
}
+ object->setInternalClass(t.lookup);
- Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1));
-
- // remove the entry in the property data
- removeFromPropertyData(object, propIdx, accessor);
-
- t.lookup = object->internalClass();
- Q_ASSERT(t.lookup);
+ // we didn't remove the data slot, just made it inaccessible
+ Q_ASSERT(object->internalClass()->size == oldClass->size);
}
uint InternalClass::find(const String *string)
@@ -415,16 +434,32 @@ InternalClass *InternalClass::sealed()
if (m_sealed)
return m_sealed;
- m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
- m_sealed = m_sealed->changePrototype(prototype);
+ bool alreadySealed = !extensible;
+ for (uint i = 0; i < size; ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ if (attrs.isEmpty())
+ continue;
+ if (attrs.isConfigurable()) {
+ alreadySealed = false;
+ break;
+ }
+ }
+
+ if (alreadySealed) {
+ m_sealed = this;
+ return this;
+ }
+
+ m_sealed = engine->newClass(this);
+
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
continue;
attrs.setConfigurable(false);
- m_sealed = m_sealed->addMember(nameMap.at(i), attrs);
+ m_sealed->propertyData.set(i, attrs);
}
- m_sealed = m_sealed->nonExtensible();
+ m_sealed->extensible = false;
m_sealed->m_sealed = m_sealed;
return m_sealed;
@@ -435,8 +470,35 @@ InternalClass *InternalClass::frozen()
if (m_frozen)
return m_frozen;
- m_frozen = propertiesFrozen();
- m_frozen = m_frozen->nonExtensible();
+ bool alreadyFrozen = !extensible;
+ for (uint i = 0; i < size; ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ if (attrs.isEmpty())
+ continue;
+ if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable()) {
+ alreadyFrozen = false;
+ break;
+ }
+ }
+
+ if (alreadyFrozen) {
+ m_frozen = this;
+ m_sealed = this;
+ return this;
+ }
+
+ m_frozen = engine->newClass(this);
+
+ for (uint i = 0; i < size; ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ if (attrs.isEmpty())
+ continue;
+ if (attrs.isData())
+ attrs.setWritable(false);
+ attrs.setConfigurable(false);
+ m_frozen->propertyData.set(i, attrs);
+ }
+ m_frozen->extensible = false;
m_frozen->m_frozen = m_frozen;
m_frozen->m_sealed = m_frozen;
@@ -468,7 +530,7 @@ InternalClass *InternalClass::asProtoClass()
if (t.lookup)
return t.lookup;
- InternalClass *newClass = engine->newClass(*this);
+ InternalClass *newClass = engine->newClass(this);
newClass->isUsedAsProto = true;
t.lookup = newClass;
@@ -505,27 +567,24 @@ void InternalClass::destroy()
}
}
+static void updateProtoUsage(Heap::Object *o, InternalClass *ic)
+{
+ if (ic->prototype == o)
+ ic->id = ic->engine->newInternalClassId();
+ for (auto &t : ic->transitions) {
+ Q_ASSERT(t.lookup);
+ updateProtoUsage(o, t.lookup);
+ }
+}
+
+
void InternalClass::updateProtoUsage(Heap::Object *o)
{
Q_ASSERT(isUsedAsProto);
InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty];
Q_ASSERT(!ic->prototype);
- // only need to go two levels into the IC hierarchy, as prototype changes
- // can only happen there
- for (auto &t : ic->transitions) {
- Q_ASSERT(t.lookup);
- if (t.flags == InternalClassTransition::VTableChange) {
- InternalClass *ic2 = t.lookup;
- for (auto &t2 : ic2->transitions) {
- if (t2.flags == InternalClassTransition::PrototypeChange &&
- t2.lookup->prototype == o)
- ic2->updateInternalClassIdRecursive();
- }
- } else if (t.flags == InternalClassTransition::PrototypeChange && t.lookup->prototype == o) {
- ic->updateInternalClassIdRecursive();
- }
- }
+ ::updateProtoUsage(o, ic);
}
void InternalClass::updateInternalClassIdRecursive()
@@ -538,26 +597,23 @@ void InternalClass::updateInternalClassIdRecursive()
}
-
-void InternalClassPool::markObjects(MarkStack *markStack)
+static void markChildren(MarkStack *markStack, InternalClass *ic)
{
- InternalClass *ic = markStack->engine->internalClasses[EngineBase::Class_Empty];
- Q_ASSERT(!ic->prototype);
+ if (ic->prototype)
+ ic->prototype->mark(markStack);
- // only need to go two levels into the IC hierarchy, as prototype changes
- // can only happen there
for (auto &t : ic->transitions) {
Q_ASSERT(t.lookup);
- if (t.flags == InternalClassTransition::VTableChange) {
- InternalClass *ic2 = t.lookup;
- for (auto &t2 : ic2->transitions) {
- if (t2.flags == InternalClassTransition::PrototypeChange)
- t2.lookup->prototype->mark(markStack);
- }
- } else if (t.flags == InternalClassTransition::PrototypeChange) {
- t.lookup->prototype->mark(markStack);
- }
+ markChildren(markStack, t.lookup);
}
}
+
+void InternalClassPool::markObjects(MarkStack *markStack)
+{
+ InternalClass *ic = markStack->engine->internalClasses[EngineBase::Class_Empty];
+ Q_ASSERT(!ic->prototype);
+ ::markChildren(markStack, ic);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index b689272006..53fc25e42b 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -79,12 +79,12 @@ struct PropertyHash
inline PropertyHash();
inline PropertyHash(const PropertyHash &other);
inline ~PropertyHash();
+ PropertyHash &operator=(const PropertyHash &other);
void addEntry(const Entry &entry, int classSize);
uint lookup(const Identifier *identifier) const;
-
-private:
- PropertyHash &operator=(const PropertyHash &other);
+ int removeIdentifier(Identifier *identifier, int classSize);
+ void detach(bool grow, int classSize);
};
struct PropertyHashData
@@ -118,6 +118,17 @@ inline PropertyHash::~PropertyHash()
delete d;
}
+inline PropertyHash &PropertyHash::operator=(const PropertyHash &other)
+{
+ ++other.d->refCount;
+ if (!--d->refCount)
+ delete d;
+ d = other.d;
+ return *this;
+}
+
+
+
inline uint PropertyHash::lookup(const Identifier *identifier) const
{
Q_ASSERT(d->entries);
@@ -163,6 +174,13 @@ struct SharedInternalClassData {
if (!--d->refcount)
delete d;
}
+ SharedInternalClassData &operator=(const SharedInternalClassData &other) {
+ ++other.d->refcount;
+ if (!--d->refcount)
+ delete d;
+ d = other.d;
+ return *this;
+ }
void add(uint pos, T value) {
if (pos < d->size) {
@@ -214,9 +232,6 @@ struct SharedInternalClassData {
Q_ASSERT(i < d->size);
return d->data[i];
}
-
-private:
- SharedInternalClassData &operator=(const SharedInternalClassData &other);
};
struct InternalClassTransition
@@ -233,7 +248,8 @@ struct InternalClassTransition
NotExtensible = 0x100,
VTableChange = 0x200,
PrototypeChange = 0x201,
- ProtoClass = 0x202
+ ProtoClass = 0x202,
+ RemoveMember = -1
};
bool operator==(const InternalClassTransition &other) const
@@ -248,6 +264,7 @@ struct InternalClass : public QQmlJS::Managed {
ExecutionEngine *engine;
const VTable *vtable;
Heap::Object *prototype;
+ InternalClass *parent = nullptr;
PropertyHash propertyTable; // id to valueIndex
SharedInternalClassData<Identifier *> nameMap;
@@ -309,7 +326,7 @@ private:
void updateInternalClassIdRecursive();
friend struct ExecutionEngine;
InternalClass(ExecutionEngine *engine);
- InternalClass(const InternalClass &other);
+ InternalClass(InternalClass *other);
};
struct InternalClassPool : public QQmlJS::MemoryPool
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 5fd200efc1..b337243204 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -78,7 +78,7 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(
void Profiler::stopProfiling()
{
featuresEnabled = 0;
- reportData(true);
+ reportData();
m_sentLocations.clear();
}
@@ -89,7 +89,7 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2)
(call1.m_end == call2.m_end && call1.m_function < call2.m_function)));
}
-void Profiler::reportData(bool trackLocations)
+void Profiler::reportData()
{
std::sort(m_data.begin(), m_data.end());
QVector<FunctionCallProperties> properties;
@@ -100,12 +100,11 @@ void Profiler::reportData(bool trackLocations)
properties.append(call.properties());
Function *function = call.function();
SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
- if (!trackLocations || !marker.isValid()) {
+ if (!marker.isValid()) {
FunctionLocation &location = locations[properties.constLast().id];
if (!location.isValid())
location = call.resolveLocation();
- if (trackLocations)
- marker.setFunction(function);
+ marker.setFunction(function);
}
}
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index e8c154e4e7..8461384e9a 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -251,7 +251,7 @@ public:
void stopProfiling();
void startProfiling(quint64 features);
- void reportData(bool trackLocations);
+ void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 5ebd385cfb..f555740455 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -56,7 +56,11 @@
#include <private/qv4functionobject_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4variantobject_p.h>
+
+#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
+#endif
+
#include <private/qv4objectproto_p.h>
#include <private/qv4jsonobject_p.h>
#include <private/qv4regexpobject_p.h>
@@ -181,11 +185,13 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object
if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property.propType()))
return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, property.propType());
} else {
+#if QT_CONFIG(qml_sequence_object)
// see if it's a sequence type
bool succeeded = false;
QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType(), object, property.coreIndex(), &succeeded));
if (succeeded)
return retn->asReturnedValue();
+#endif
}
if (property.propType() == QMetaType::UnknownType) {
@@ -1611,6 +1617,7 @@ void CallArgument::initAsType(int callType)
}
}
+#if QT_CONFIG(qml_sequence_object)
template <class T, class M>
void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
{
@@ -1623,6 +1630,7 @@ void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M
}
}
}
+#endif
void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value)
{
@@ -1705,6 +1713,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
type = callType;
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
+#if QT_CONFIG(qml_sequence_object)
} else if (callType == qMetaTypeId<std::vector<int>>()
|| callType == qMetaTypeId<std::vector<qreal>>()
|| callType == qMetaTypeId<std::vector<bool>>()
@@ -1732,6 +1741,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
stdVectorQModelIndexPtr = nullptr;
fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
}
+#endif
} else {
queryEngine = true;
}
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index e9bef2f604..eab1ffb5d7 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -59,6 +59,8 @@
#include "qv4context_p.h"
#include "qv4string_p.h"
+QT_REQUIRE_CONFIG(qml_sequence_object);
+
QT_BEGIN_NAMESPACE
namespace QV4 {
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 14def49d0a..31b51cbfe3 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -40,13 +40,17 @@
#include "qv4serialize_p.h"
#include <private/qv8engine_p.h>
+#if QT_CONFIG(qml_list_model)
#include <private/qqmllistmodel_p.h>
#include <private/qqmllistmodelworkeragent_p.h>
+#endif
#include <private/qv4value_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4regexpobject_p.h>
+#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
+#endif
#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
@@ -82,8 +86,12 @@ enum Type {
WorkerNumber,
WorkerDate,
WorkerRegexp,
+#if QT_CONFIG(qml_list_model)
WorkerListModel,
+#endif
+#if QT_CONFIG(qml_sequence_object)
WorkerSequence
+#endif
};
static inline quint32 valueheader(Type type, quint32 size = 0)
@@ -228,6 +236,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
} else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) {
// XXX TODO: Generalize passing objects between the main thread and worker scripts so
// that others can trivially plug in their elements.
+#if QT_CONFIG(qml_list_model)
QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object());
if (lm && lm->agent()) {
QQmlListModelWorkerAgent *agent = lm->agent();
@@ -236,9 +245,13 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
push(data, (void *)agent);
return;
}
+#else
+ Q_UNUSED(qobjectWrapper);
+#endif
// No other QObject's are allowed to be sent
push(data, valueheader(WorkerUndefined));
} else if (const Object *o = v.as<Object>()) {
+#if QT_CONFIG(qml_sequence_object)
if (o->isListType()) {
// valid sequence. we generate a length (sequence length + 1 for the sequence type)
uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32();
@@ -256,6 +269,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
return;
}
+#endif
// regular object
QV4::ScopedValue val(scope, v);
@@ -353,6 +367,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
data += ALIGN(length * sizeof(quint16));
return Encode(engine->newRegExpObject(pattern, flags));
}
+#if QT_CONFIG(qml_list_model)
case WorkerListModel:
{
void *ptr = popPtr(data);
@@ -369,6 +384,8 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
agent->setEngine(engine);
return rv->asReturnedValue();
}
+#endif
+#if QT_CONFIG(qml_sequence_object)
case WorkerSequence:
{
ScopedValue value(scope);
@@ -387,6 +404,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded);
return QV4::SequencePrototype::fromVariant(engine, seqVariant, &succeeded);
}
+#endif
}
Q_ASSERT(!"Unreachable");
return QV4::Encode::undefined();
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 53933cd090..403f400bee 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -65,8 +65,6 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct InternalClass;
-
struct VTable
{
const VTable * const parent;
@@ -88,17 +86,42 @@ struct VTable
namespace Heap {
+template <typename T, size_t o>
+struct Pointer {
+ static Q_CONSTEXPR size_t offset = o;
+ T operator->() const { return get(); }
+ operator T () const { return get(); }
+
+ Base *base();
+
+ void set(EngineBase *e, T newVal) {
+ WriteBarrier::write(e, base(), &ptr, reinterpret_cast<Base *>(newVal));
+ }
+
+ T get() const { return reinterpret_cast<T>(ptr); }
+
+ template <typename Type>
+ Type *cast() { return static_cast<Type *>(ptr); }
+
+ Base *heapObject() const { return ptr; }
+
+private:
+ Base *ptr;
+};
+typedef Pointer<char *, 0> V4PointerCheck;
+Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
+
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
- static void markObjects(Heap::Base *, MarkStack *) {}
+ static void markObjects(Base *, MarkStack *) {}
InternalClass *internalClass;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::MarkStack *markStack);
- const VTable *vtable() const { return internalClass->vtable; }
+ inline const VTable *vtable() const;
inline bool isMarked() const {
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
Chunk *c = h->chunk();
@@ -130,8 +153,8 @@ struct Q_QML_EXPORT Base {
}
void *operator new(size_t, Managed *m) { return m; }
- void *operator new(size_t, Heap::Base *m) { return m; }
- void operator delete(void *, Heap::Base *) {}
+ void *operator new(size_t, Base *m) { return m; }
+ void operator delete(void *, Base *) {}
void init() { _setInitialized(); }
void destroy() { _setDestroyed(); }
@@ -178,10 +201,9 @@ Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0);
Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
-}
inline
-void Heap::Base::mark(QV4::MarkStack *markStack)
+void Base::mark(QV4::MarkStack *markStack)
{
Q_ASSERT(inUse());
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
@@ -196,36 +218,18 @@ void Heap::Base::mark(QV4::MarkStack *markStack)
}
}
-namespace Heap {
-
-template <typename T, size_t o>
-struct Pointer {
- static Q_CONSTEXPR size_t offset = o;
- T operator->() const { return get(); }
- operator T () const { return get(); }
-
- Heap::Base *base() {
- Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
- Q_ASSERT(base->inUse());
- return base;
- }
-
- void set(EngineBase *e, T newVal) {
- WriteBarrier::write(e, base(), &ptr, reinterpret_cast<Heap::Base *>(newVal));
- }
-
- T get() const { return reinterpret_cast<T>(ptr); }
-
- template <typename Type>
- Type *cast() { return static_cast<Type *>(ptr); }
-
- Heap::Base *heapObject() const { return ptr; }
+inline
+const VTable *Base::vtable() const
+{
+ return internalClass->vtable;
+}
-private:
- Heap::Base *ptr;
-};
-typedef Pointer<char *, 0> V4PointerCheck;
-Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
+template<typename T, size_t o>
+Base *Pointer<T, o>::base() {
+ Base *base = reinterpret_cast<Base *>(this) - (offset/sizeof(Base *));
+ Q_ASSERT(base->inUse());
+ return base;
+}
}
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
index b4f0debf85..97ce6ebea3 100644
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ b/src/qml/parser/qqmljsengine_p.cpp
@@ -112,13 +112,6 @@ double integerFromString(const char *buf, int size, int radix)
return result;
}
-double integerFromString(const QString &str, int radix)
-{
- QByteArray ba = QStringRef(&str).trimmed().toLatin1();
- return integerFromString(ba.constData(), ba.size(), radix);
-}
-
-
Engine::Engine()
: _lexer(nullptr), _directives(nullptr)
{ }
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index aab9025a08..2414f92e50 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -87,12 +87,11 @@ Lexer::Lexer(Engine *engine)
: _engine(engine)
, _codePtr(nullptr)
, _endPtr(nullptr)
- , _lastLinePtr(nullptr)
- , _tokenLinePtr(nullptr)
, _tokenStartPtr(nullptr)
, _char(QLatin1Char('\n'))
, _errorCode(NoError)
, _currentLineNumber(0)
+ , _currentColumnNumber(0)
, _tokenValue(0)
, _parenthesesState(IgnoreParentheses)
, _parenthesesCount(0)
@@ -101,6 +100,7 @@ Lexer::Lexer(Engine *engine)
, _tokenKind(0)
, _tokenLength(0)
, _tokenLine(0)
+ , _tokenColumn(0)
, _validTokenText(false)
, _prohibitAutomaticSemicolon(false)
, _restrictedKeyword(false)
@@ -137,14 +137,13 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_codePtr = code.unicode();
_endPtr = _codePtr + code.length();
- _lastLinePtr = _codePtr;
- _tokenLinePtr = _codePtr;
_tokenStartPtr = _codePtr;
_char = QLatin1Char('\n');
_errorCode = NoError;
_currentLineNumber = lineno;
+ _currentColumnNumber = 0;
_tokenValue = 0;
// parentheses state
@@ -156,6 +155,7 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_patternFlags = 0;
_tokenLength = 0;
_tokenLine = lineno;
+ _tokenColumn = 0;
_validTokenText = false;
_prohibitAutomaticSemicolon = false;
@@ -172,9 +172,10 @@ void Lexer::scanChar()
if (sequenceLength == 2)
_char = *_codePtr++;
- if (unsigned sequenceLength = isLineTerminatorSequence()) {
- _lastLinePtr = _codePtr + sequenceLength - 1; // points to the first character after the newline
+ ++_currentColumnNumber;
+ if (isLineTerminator()) {
++_currentLineNumber;
+ _currentColumnNumber = 0;
}
}
@@ -222,6 +223,25 @@ inline bool isBinop(int tok)
return false;
}
}
+
+int hexDigit(QChar c)
+{
+ if (c >= QLatin1Char('0') && c <= QLatin1Char('9'))
+ return c.unicode() - '0';
+ if (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
+ return c.unicode() - 'a' + 10;
+ if (c >= QLatin1Char('A') && c <= QLatin1Char('F'))
+ return c.unicode() - 'A' + 10;
+ return -1;
+}
+
+int octalDigit(QChar c)
+{
+ if (c >= QLatin1Char('0') && c <= QLatin1Char('7'))
+ return c.unicode() - '0';
+ return -1;
+}
+
} // anonymous namespace
int Lexer::lex()
@@ -295,39 +315,57 @@ int Lexer::lex()
return _tokenKind;
}
-bool Lexer::isUnicodeEscapeSequence(const QChar *chars)
-{
- if (isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3]))
- return true;
-
- return false;
-}
-
-QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok)
+uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
{
- if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) {
- scanChar(); // skip u
+ Q_ASSERT(_char == QLatin1Char('u'));
+ scanChar(); // skip u
+ if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) {
+ uint codePoint = 0;
+ for (int i = 0; i < 4; ++i) {
+ int digit = hexDigit(_char);
+ if (digit < 0)
+ goto error;
+ codePoint *= 16;
+ codePoint += digit;
+ scanChar();
+ }
- const QChar c1 = _char;
- scanChar();
+ *ok = true;
+ return codePoint;
+ } else if (_codePtr < _endPtr && _char == QLatin1Char('{')) {
+ scanChar(); // skip '{'
+ uint codePoint = 0;
+ if (!isHexDigit(_char))
+ // need at least one hex digit
+ goto error;
- const QChar c2 = _char;
- scanChar();
+ while (_codePtr <= _endPtr) {
+ int digit = hexDigit(_char);
+ if (digit < 0)
+ break;
+ codePoint *= 16;
+ codePoint += digit;
+ if (codePoint > 0x10ffff)
+ goto error;
+ scanChar();
+ }
- const QChar c3 = _char;
- scanChar();
+ if (_char != QLatin1Char('}'))
+ goto error;
- const QChar c4 = _char;
- scanChar();
+ scanChar(); // skip '}'
- if (ok)
- *ok = true;
- return convertUnicode(c1, c2, c3, c4);
+ *ok = true;
+ return codePoint;
}
+ error:
+ _errorCode = IllegalUnicodeEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+
*ok = false;
- return QChar();
+ return 0;
}
QChar Lexer::decodeHexEscapeCharacter(bool *ok)
@@ -351,15 +389,15 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
return QChar();
}
-static inline bool isIdentifierStart(QChar ch)
+static inline bool isIdentifierStart(uint ch)
{
// fast path for ascii
- if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') ||
- (ch.unicode() >= 'A' && ch.unicode() <= 'Z') ||
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
ch == '$' || ch == '_')
return true;
- switch (ch.category()) {
+ switch (QChar::category(ch)) {
case QChar::Number_Letter:
case QChar::Letter_Uppercase:
case QChar::Letter_Lowercase:
@@ -373,17 +411,17 @@ static inline bool isIdentifierStart(QChar ch)
return false;
}
-static bool isIdentifierPart(QChar ch)
+static bool isIdentifierPart(uint ch)
{
// fast path for ascii
- if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') ||
- (ch.unicode() >= 'A' && ch.unicode() <= 'Z') ||
- (ch.unicode() >= '0' && ch.unicode() <= '9') ||
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
ch == '$' || ch == '_' ||
- ch.unicode() == 0x200c /* ZWNJ */ || ch.unicode() == 0x200d /* ZWJ */)
+ ch == 0x200c /* ZWNJ */ || ch == 0x200d /* ZWJ */)
return true;
- switch (ch.category()) {
+ switch (QChar::category(ch)) {
case QChar::Mark_NonSpacing:
case QChar::Mark_SpacingCombining:
@@ -416,15 +454,13 @@ int Lexer::scanToken()
again:
_validTokenText = false;
- _tokenLinePtr = _lastLinePtr;
while (_char.isSpace()) {
- if (unsigned sequenceLength = isLineTerminatorSequence()) {
- _tokenLinePtr = _codePtr + sequenceLength - 1;
-
+ if (isLineTerminator()) {
if (_restrictedKeyword) {
// automatic semicolon insertion
_tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
_tokenStartPtr = _codePtr - 1;
return T_SEMICOLON;
} else {
@@ -438,6 +474,7 @@ again:
_tokenStartPtr = _codePtr - 1;
_tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
if (_codePtr > _endPtr)
return EOF_SYMBOL;
@@ -557,51 +594,8 @@ again:
return T_DIVIDE_;
case '.':
- if (_char.isDigit()) {
- QVarLengthArray<char,32> chars;
-
- chars.append(ch.unicode()); // append the `.'
-
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar();
- }
-
- if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
- _codePtr[1].isDigit())) {
-
- chars.append(_char.unicode());
- scanChar(); // consume `e'
-
- if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
- chars.append(_char.unicode());
- scanChar(); // consume the sign
- }
-
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar();
- }
- }
- }
-
- chars.append('\0');
-
- const char *begin = chars.constData();
- const char *end = nullptr;
- bool ok = false;
-
- _tokenValue = qstrtod(begin, &end, &ok);
-
- if (end - begin != chars.size() - 1) {
- _errorCode = IllegalExponentIndicator;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
- return T_ERROR;
- }
-
- return T_NUMERIC_LITERAL;
- }
+ if (isDecimalDigit(_char.unicode()))
+ return scanNumber(ch);
return T_DOT;
case '-':
@@ -737,11 +731,15 @@ again:
// unicode escape sequence
case 'u': {
bool ok = false;
- u = decodeUnicodeEscapeCharacter(&ok);
- if (! ok) {
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ uint codePoint = decodeUnicodeEscapeCharacter(&ok);
+ if (!ok)
return T_ERROR;
+ if (QChar::requiresSurrogates(codePoint)) {
+ // need to use a surrogate pair
+ _tokenText += QChar(QChar::highSurrogate(codePoint));
+ u = QChar::lowSurrogate(codePoint);
+ } else {
+ u = codePoint;
}
} break;
@@ -824,28 +822,36 @@ again:
return scanNumber(ch);
default: {
- QChar c = ch;
+ uint c = ch.unicode();
bool identifierWithEscapeChars = false;
- if (c == QLatin1Char('\\') && _char == QLatin1Char('u')) {
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) {
+ c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ scanChar();
+ } else if (c == '\\' && _char == QLatin1Char('u')) {
identifierWithEscapeChars = true;
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
- if (! ok) {
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ if (!ok)
return T_ERROR;
- }
}
if (isIdentifierStart(c)) {
if (identifierWithEscapeChars) {
_tokenText.resize(0);
- _tokenText += c;
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
+ }
_validTokenText = true;
}
- while (true) {
- c = _char;
- if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
- if (! identifierWithEscapeChars) {
+ while (_codePtr <= _endPtr) {
+ c = _char.unicode();
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) {
+ scanChar();
+ c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
+ if (!identifierWithEscapeChars) {
identifierWithEscapeChars = true;
_tokenText.resize(0);
_tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
@@ -855,38 +861,52 @@ again:
scanChar(); // skip '\\'
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
- if (! ok) {
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ if (!ok)
return T_ERROR;
- }
- if (isIdentifierPart(c))
- _tokenText += c;
- continue;
- } else if (isIdentifierPart(c)) {
- if (identifierWithEscapeChars)
- _tokenText += c;
- scanChar();
+ if (!isIdentifierPart(c))
+ break;
+
+ if (identifierWithEscapeChars) {
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
+ }
+ }
continue;
}
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ if (!isIdentifierPart(c))
+ break;
+
+ if (identifierWithEscapeChars) {
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
+ }
+ }
+ scanChar();
+ }
- int kind = T_IDENTIFIER;
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
- if (! identifierWithEscapeChars)
- kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
+ int kind = T_IDENTIFIER;
- if (_engine) {
- if (kind == T_IDENTIFIER && identifierWithEscapeChars)
- _tokenSpell = _engine->newStringRef(_tokenText);
- else
- _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
- }
+ if (!identifierWithEscapeChars)
+ kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
- return kind;
+ if (_engine) {
+ if (kind == T_IDENTIFIER && identifierWithEscapeChars)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+ else
+ _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
}
+
+ return kind;
}
}
@@ -898,91 +918,110 @@ again:
int Lexer::scanNumber(QChar ch)
{
- if (ch != QLatin1Char('0')) {
- QVarLengthArray<char, 64> buf;
- buf += ch.toLatin1();
-
- QChar n = _char;
- const QChar *code = _codePtr;
- while (n.isDigit()) {
- buf += n.toLatin1();
- n = *code++;
- }
+ if (ch == QLatin1Char('0')) {
+ if (_char == QLatin1Char('x') || _char == QLatin1Char('X')) {
+ ch = _char; // remember the x or X to use it in the error message below.
+
+ // parse hex integer literal
+ scanChar(); // consume 'x'
+
+ if (!isHexDigit(_char)) {
+ _errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
+ return T_ERROR;
+ }
- if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
- if (code != _codePtr) {
- _codePtr = code - 1;
+ double d = 0.;
+ while (1) {
+ int digit = ::hexDigit(_char);
+ if (digit < 0)
+ break;
+ d *= 16;
+ d += digit;
scanChar();
}
- buf.append('\0');
- _tokenValue = strtod(buf.constData(), nullptr);
+
+ _tokenValue = d;
return T_NUMERIC_LITERAL;
- }
- } else if (_char.isDigit() && !qmlMode()) {
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
- return T_ERROR;
- }
+ } else if (_char == QLatin1Char('o') || _char == QLatin1Char('O')) {
+ ch = _char; // remember the o or O to use it in the error message below.
- QVarLengthArray<char,32> chars;
- chars.append(ch.unicode());
+ // parse octal integer literal
+ scanChar(); // consume 'o'
- if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
- ch = _char; // remember the x or X to use it in the error message below.
+ if (!isOctalDigit(_char.unicode())) {
+ _errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "At least one octal digit is required after '0%1'").arg(ch);
+ return T_ERROR;
+ }
- // parse hex integer literal
- chars.append(_char.unicode());
- scanChar(); // consume `x'
+ double d = 0.;
+ while (1) {
+ int digit = ::octalDigit(_char);
+ if (digit < 0)
+ break;
+ d *= 8;
+ d += digit;
+ scanChar();
+ }
- while (isHexDigit(_char)) {
- chars.append(_char.unicode());
- scanChar();
- }
+ _tokenValue = d;
+ return T_NUMERIC_LITERAL;
+ } else if (_char == QLatin1Char('b') || _char == QLatin1Char('B')) {
+ ch = _char; // remember the b or B to use it in the error message below.
+
+ // parse binary integer literal
+ scanChar(); // consume 'b'
- if (chars.size() < 3) {
- _errorCode = IllegalHexNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
+ if (_char.unicode() != '0' && _char.unicode() != '1') {
+ _errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "At least one binary digit is required after '0%1'").arg(ch);
+ return T_ERROR;
+ }
+
+ double d = 0.;
+ while (1) {
+ int digit = 0;
+ if (_char.unicode() == '1')
+ digit = 1;
+ else if (_char.unicode() != '0')
+ break;
+ d *= 2;
+ d += digit;
+ scanChar();
+ }
+
+ _tokenValue = d;
+ return T_NUMERIC_LITERAL;
+ } else if (_char.isDigit() && !qmlMode()) {
+ _errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
return T_ERROR;
}
-
- _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
- return T_NUMERIC_LITERAL;
}
// decimal integer literal
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar(); // consume the digit
- }
-
- if (_char == QLatin1Char('.')) {
- chars.append(_char.unicode());
- scanChar(); // consume `.'
+ QVarLengthArray<char,32> chars;
+ chars.append(ch.unicode());
+ if (ch != QLatin1Char('.')) {
while (_char.isDigit()) {
chars.append(_char.unicode());
- scanChar();
+ scanChar(); // consume the digit
}
- if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
- _codePtr[1].isDigit())) {
-
- chars.append(_char.unicode());
- scanChar(); // consume `e'
+ if (_char == QLatin1Char('.')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume `.'
+ }
+ }
- if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
- chars.append(_char.unicode());
- scanChar(); // consume the sign
- }
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar();
- }
- }
- }
- } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
_codePtr[1].isDigit())) {
@@ -1001,12 +1040,6 @@ int Lexer::scanNumber(QChar ch)
}
}
- if (chars.length() == 1) {
- // if we ended up with a single digit, then it was a '0'
- _tokenValue = 0;
- return T_NUMERIC_LITERAL;
- }
-
chars.append('\0');
const char *begin = chars.constData();
@@ -1174,16 +1207,6 @@ bool Lexer::isOctalDigit(ushort c)
return (c >= '0' && c <= '7');
}
-int Lexer::tokenEndLine() const
-{
- return _currentLineNumber;
-}
-
-int Lexer::tokenEndColumn() const
-{
- return _codePtr - _lastLinePtr;
-}
-
QString Lexer::tokenText() const
{
if (_validTokenText)
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index 11d8081713..eca5d932b4 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -124,7 +124,7 @@ public:
enum Error {
NoError,
IllegalCharacter,
- IllegalHexNumber,
+ IllegalNumber,
UnclosedStringLiteral,
IllegalEscapeSequence,
IllegalUnicodeEscapeSequence,
@@ -166,10 +166,7 @@ public:
int tokenLength() const { return _tokenLength; }
int tokenStartLine() const { return _tokenLine; }
- int tokenStartColumn() const { return _tokenStartPtr - _tokenLinePtr + 1; }
-
- int tokenEndLine() const;
- int tokenEndColumn() const;
+ int tokenStartColumn() const { return _tokenColumn; }
inline QStringRef tokenSpell() const { return _tokenSpell; }
double tokenValue() const { return _tokenValue; }
@@ -202,10 +199,9 @@ private:
static bool isDecimalDigit(ushort c);
static bool isHexDigit(QChar c);
static bool isOctalDigit(ushort c);
- static bool isUnicodeEscapeSequence(const QChar *chars);
void syncProhibitAutomaticSemicolon();
- QChar decodeUnicodeEscapeCharacter(bool *ok);
+ uint decodeUnicodeEscapeCharacter(bool *ok);
QChar decodeHexEscapeCharacter(bool *ok);
private:
@@ -218,14 +214,13 @@ private:
const QChar *_codePtr;
const QChar *_endPtr;
- const QChar *_lastLinePtr;
- const QChar *_tokenLinePtr;
const QChar *_tokenStartPtr;
QChar _char;
Error _errorCode;
int _currentLineNumber;
+ int _currentColumnNumber;
double _tokenValue;
// parentheses state
@@ -238,6 +233,7 @@ private:
int _tokenKind;
int _tokenLength;
int _tokenLine;
+ int _tokenColumn;
bool _validTokenText;
bool _prohibitAutomaticSemicolon;
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index f75bfa0313..eabca59836 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -72,7 +72,7 @@ include(jsruntime/jsruntime.pri)
include(jit/jit.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
-qtConfig(animation) {
+qtConfig(qml-animation) {
include(animations/animations.pri)
}
include(types/types.pri)
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 412dc6cba2..6d69294c17 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -20,7 +20,6 @@ SOURCES += \
$$PWD/qqmlinfo.cpp \
$$PWD/qqmlerror.cpp \
$$PWD/qqmlvaluetype.cpp \
- $$PWD/qqmlxmlhttprequest.cpp \
$$PWD/qqmlcleanup.cpp \
$$PWD/qqmlpropertycache.cpp \
$$PWD/qqmlnotifier.cpp \
@@ -31,7 +30,6 @@ SOURCES += \
$$PWD/qqmlextensionplugin.cpp \
$$PWD/qqmlimport.cpp \
$$PWD/qqmllist.cpp \
- $$PWD/qqmllocale.cpp \
$$PWD/qqmljavascriptexpression.cpp \
$$PWD/qqmlabstractbinding.cpp \
$$PWD/qqmlvaluetypeproxybinding.cpp \
@@ -85,7 +83,6 @@ HEADERS += \
$$PWD/qqmldata_p.h \
$$PWD/qqmlerror.h \
$$PWD/qqmlvaluetype_p.h \
- $$PWD/qqmlxmlhttprequest_p.h \
$$PWD/qqmlcleanup_p.h \
$$PWD/qqmlpropertycache_p.h \
$$PWD/qqmlpropertyindex_p.h \
@@ -99,7 +96,6 @@ HEADERS += \
$$PWD/qqmlimport_p.h \
$$PWD/qqmlextensionplugin.h \
$$PWD/qqmlscriptstring_p.h \
- $$PWD/qqmllocale_p.h \
$$PWD/qqmlcomponentattached_p.h \
$$PWD/qqmljavascriptexpression_p.h \
$$PWD/qqmlabstractbinding_p.h \
@@ -120,5 +116,22 @@ HEADERS += \
$$PWD/qqmldelayedcallqueue_p.h \
$$PWD/qqmlloggingcategory_p.h
+qtConfig(qml-xml-http-request) {
+ HEADERS += \
+ $$PWD/qqmlxmlhttprequest_p.h
+
+ SOURCES += \
+ $$PWD/qqmlxmlhttprequest.cpp
+
+}
+
+qtConfig(qml-locale) {
+ HEADERS += \
+ $$PWD/qqmllocale_p.h
+
+ SOURCES += \
+ $$PWD/qqmllocale.cpp
+}
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 4054d2f0be..0e74baf684 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -48,7 +48,6 @@
#include "qqmlcomponent.h"
#include "qqmlvme_p.h"
#include "qqmlstringconverters_p.h"
-#include "qqmlxmlhttprequest_p.h"
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlcomponent_p.h"
@@ -79,13 +78,17 @@
#include <private/qobject_p.h>
#include <private/qmetaobject_p.h>
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <private/qqmlbind_p.h>
#include <private/qqmlconnections_p.h>
-#if QT_CONFIG(animation)
+#if QT_CONFIG(qml_animation)
#include <private/qqmltimer_p.h>
#endif
+#if QT_CONFIG(qml_list_model)
#include <private/qqmllistmodel_p.h>
+#endif
#include <private/qqmlplatform_p.h>
#include <private/qquickpackage_p.h>
#include <private/qqmldelegatemodel_p.h>
@@ -223,7 +226,7 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8
qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3
qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections");
-#if QT_CONFIG(animation)
+#if QT_CONFIG(qml_animation)
qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer");
#endif
qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1
@@ -236,8 +239,10 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
// These QtQuick types' implementation resides in the QtQml module
void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor)
{
+#if QT_CONFIG(qml_list_model)
qmlRegisterType<QQmlListElement>(uri, versionMajor, versionMinor, "ListElement"); // Now in QtQml.Models, here for compatibility
qmlRegisterCustomType<QQmlListModel>(uri, versionMajor, versionMinor, "ListModel", new QQmlListModelParser); // Now in QtQml.Models, here for compatibility
+#endif
qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
qmlRegisterType<QQuickPackage>(uri, versionMajor, versionMinor, "Package");
qmlRegisterType<QQmlDelegateModel>(uri, versionMajor, versionMinor, "VisualDataModel");
@@ -252,7 +257,9 @@ void QQmlEnginePrivate::defineQtQuick2Module()
// register the QtQuick2 types which are implemented in the QtQml module.
registerQtQuick2Types("QtQuick",2,0);
+#if QT_CONFIG(qml_locale)
qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+#endif
}
bool QQmlEnginePrivate::designerMode()
@@ -950,7 +957,9 @@ void QQmlEnginePrivate::init()
if (baseModulesUninitialized) {
qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component"); // required for the Compiler.
registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
+#if QT_CONFIG(qml_locale)
qmlRegisterUncreatableType<QQmlLocale>("QtQml", 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+#endif
QQmlData::init();
baseModulesUninitialized = false;
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 8341b1f555..859c36e11b 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -58,6 +58,8 @@
#include <private/qqmlglobal_p.h>
#include <private/qv4object_p.h>
+QT_REQUIRE_CONFIG(qml_locale);
+
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h
index f2836d8301..7515ef8dcc 100644
--- a/src/qml/qml/qqmlxmlhttprequest_p.h
+++ b/src/qml/qml/qqmlxmlhttprequest_p.h
@@ -55,7 +55,7 @@
#include <QtCore/qglobal.h>
#include <private/qqmlglobal_p.h>
-#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
+QT_REQUIRE_CONFIG(qml_xml_http_request);
QT_BEGIN_NAMESPACE
@@ -64,7 +64,5 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *);
QT_END_NAMESPACE
-#endif // xmlstreamreader && qml_network
-
#endif // QQMLXMLHTTPREQUEST_P_H
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index c147feeb73..0e1d9e6fad 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -44,7 +44,9 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlstringconverters_p.h>
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <private/qv8engine_p.h>
#include <private/qqmldelayedcallqueue_p.h>
#include <QFileInfo>
@@ -138,7 +140,9 @@ void Heap::QtObject::init(QQmlEngine *qmlEngine)
o->defineDefaultProperty(QStringLiteral("btoa"), QV4::QtObject::method_btoa);
o->defineDefaultProperty(QStringLiteral("atob"), QV4::QtObject::method_atob);
o->defineDefaultProperty(QStringLiteral("resolvedUrl"), QV4::QtObject::method_resolvedUrl);
+#if QT_CONFIG(qml_locale)
o->defineDefaultProperty(QStringLiteral("locale"), QV4::QtObject::method_locale);
+#endif
o->defineDefaultProperty(QStringLiteral("binding"), QV4::QtObject::method_binding);
if (qmlEngine) {
@@ -1299,6 +1303,7 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va
return QV4::QObjectWrapper::wrap(scope.engine, c);
}
+#if QT_CONFIG(qml_locale)
/*!
\qmlmethod Qt::locale(name)
@@ -1333,6 +1338,7 @@ ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, co
return QQmlLocale::locale(scope.engine, code);
}
+#endif
void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction)
{
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 104dae5d79..993e323e51 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -123,7 +123,9 @@ struct QtObject : Object
static ReturnedValue method_resolvedUrl(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_createQmlObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_createComponent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+#if QT_CONFIG(qml_locale)
static ReturnedValue method_locale(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+#endif
static ReturnedValue method_binding(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 038a75d50a..92a86aa9e5 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -39,14 +39,21 @@
#include "qv8engine_p.h"
+#if QT_CONFIG(qml_sequence_object)
#include "qv4sequenceobject_p.h"
+#endif
+
#include "private/qjsengine_p.h"
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmllist_p.h>
#include <private/qqmlengine_p.h>
+#if QT_CONFIG(qml_xml_http_request)
#include <private/qqmlxmlhttprequest_p.h>
+#endif
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <private/qqmlglobal_p.h>
#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmlplatform_p.h>
@@ -123,11 +130,12 @@ static void restoreJSValue(QDataStream &stream, void *data)
}
}
-QV8Engine::QV8Engine(QJSEngine *qq, QV4::ExecutionEngine *v4)
- : q(qq)
- , m_engine(nullptr)
+QV8Engine::QV8Engine(QV4::ExecutionEngine *v4)
+ : m_engine(nullptr)
, m_v4Engine(v4)
+#if QT_CONFIG(qml_xml_http_request)
, m_xmlHttpRequestData(nullptr)
+#endif
{
#ifdef Q_PROCESSOR_X86_32
if (!qCpuHasFeature(SSE2)) {
@@ -157,7 +165,7 @@ QV8Engine::~QV8Engine()
qDeleteAll(m_extensionData);
m_extensionData.clear();
-#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
+#if QT_CONFIG(qml_xml_http_request)
qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData);
m_xmlHttpRequestData = nullptr;
#endif
@@ -183,11 +191,13 @@ void QV8Engine::initializeGlobal()
QV4::ScopedObject qt(scope, m_v4Engine->memoryManager->allocObject<QV4::QtObject>(m_engine));
m_v4Engine->globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
+#if QT_CONFIG(qml_locale)
QQmlLocale::registerStringLocaleCompare(m_v4Engine);
QQmlDateExtension::registerExtension(m_v4Engine);
QQmlNumberExtension::registerExtension(m_v4Engine);
+#endif
-#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
+#if QT_CONFIG(qml_xml_http_request)
qt_add_domexceptions(m_v4Engine);
m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine);
#endif
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index b6a378667e..d90f1827fe 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -154,10 +154,9 @@ class Q_QML_PRIVATE_EXPORT QV8Engine
friend class QJSEngine;
public:
// static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
- static QV4::ExecutionEngine *getV4(QJSEngine *q) { return q->handle(); }
static QV4::ExecutionEngine *getV4(QV8Engine *d) { return d->m_v4Engine; }
- QV8Engine(QJSEngine* qq, QV4::ExecutionEngine *v4);
+ QV8Engine(QV4::ExecutionEngine *v4);
virtual ~QV8Engine();
// This enum should be in sync with QQmlEngine::ObjectOwnership
@@ -170,10 +169,11 @@ public:
void initQmlGlobalObject();
void setEngine(QQmlEngine *engine);
QQmlEngine *engine() { return m_engine; }
- QJSEngine *publicEngine() { return q; }
QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; }
+#if QT_CONFIG(qml_xml_http_request)
void *xmlHttpRequestData() const { return m_xmlHttpRequestData; }
+#endif
void freezeObject(const QV4::Value &value);
@@ -202,13 +202,14 @@ public:
int consoleCountHelper(const QString &file, quint16 line, quint16 column);
protected:
- QJSEngine* q;
QQmlEngine *m_engine;
QQmlDelayedCallQueue m_delayedCallQueue;
QV4::ExecutionEngine *m_v4Engine;
+#if QT_CONFIG(qml_xml_http_request)
void *m_xmlHttpRequestData;
+#endif
QVector<Deletable *> m_extensionData;
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 6e92867cf5..e02dfa5ed4 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -52,6 +52,7 @@
# endif
#else
# define QT_FEATURE_qml_debug -1
+# define QT_FEATURE_qml_sequence_object 1
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 44166e4aa8..29e0baa3ac 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -487,6 +487,125 @@ void QQmlDelegateModel::setRootIndex(const QVariant &root)
}
/*!
+ \qmlproperty int QtQml.Models::DelegateModel::rows
+
+ Contains the number of rows in the model. If the model
+ is a list of items, it will be equal to the number of items
+ in the list.
+
+ \since QtQml.Models 2.12
+*/
+int QQmlDelegateModel::rows() const
+{
+ Q_D(const QQmlDelegateModel);
+ return d->m_adaptorModel.rowCount();
+}
+
+void QQmlDelegateModelPrivate::setRows(int rows)
+{
+ Q_Q(QQmlDelegateModel);
+ const bool changed = m_adaptorModel.rowCount() != rows;
+
+ if (changed || !m_adaptorModel.isValid()) {
+ const int oldCount = m_count;
+
+ if (rows > 0)
+ m_adaptorModel.rows = rows;
+ else
+ m_adaptorModel.rows.invalidate();
+
+ // Check if the previous layout was invalidated, and if so, reconnect the model
+ if (!m_adaptorModel.isValid() && m_adaptorModel.aim())
+ m_adaptorModel.setModel(m_adaptorModel.list.list(), q, m_context->engine());
+
+ if (m_adaptorModel.canFetchMore())
+ m_adaptorModel.fetchMore();
+
+ if (m_complete) {
+ const int newCount = m_adaptorModel.count();
+ if (oldCount)
+ q->_q_itemsRemoved(0, oldCount);
+ if (newCount)
+ q->_q_itemsInserted(0, newCount);
+ }
+
+ if (changed)
+ emit q->rowsChanged();
+ }
+}
+
+void QQmlDelegateModel::setRows(int rows)
+{
+ Q_D(QQmlDelegateModel);
+ d->setRows(rows);
+}
+
+void QQmlDelegateModel::resetRows()
+{
+ Q_D(QQmlDelegateModel);
+ d->setRows(-1);
+}
+
+/*!
+ \qmlproperty int QtQml.Models::DelegateModel::columns
+
+ Contains the number of columns in the model. If the model
+ is a list of items, it will be equal to \c 1.
+
+ \since QtQml.Models 2.12
+*/
+int QQmlDelegateModel::columns() const
+{
+ Q_D(const QQmlDelegateModel);
+ return d->m_adaptorModel.columnCount();
+}
+
+void QQmlDelegateModelPrivate::setColumns(int columns)
+{
+ Q_Q(QQmlDelegateModel);
+ const bool changed = m_adaptorModel.columnCount() != columns;
+
+ if (changed || !m_adaptorModel.isValid()) {
+ const int oldCount = m_count;
+
+ if (columns > 1)
+ m_adaptorModel.columns = columns;
+ else
+ m_adaptorModel.columns.invalidate();
+
+ // Check if the previous layout was invalidated, and if so, reconnect the model
+ if (!m_adaptorModel.isValid() && m_adaptorModel.aim())
+ m_adaptorModel.setModel(m_adaptorModel.list.list(), q, m_context->engine());
+
+ if (m_adaptorModel.canFetchMore())
+ m_adaptorModel.fetchMore();
+
+ if (m_complete) {
+ const int newCount = m_adaptorModel.count();
+ if (oldCount)
+ q->_q_itemsRemoved(0, oldCount);
+ if (newCount)
+ q->_q_itemsInserted(0, newCount);
+ }
+
+ if (changed)
+ emit q->columnsChanged();
+ }
+}
+
+void QQmlDelegateModel::setColumns(int columns)
+{
+ Q_D(QQmlDelegateModel);
+ d->setColumns(columns);
+}
+
+void QQmlDelegateModel::resetColumns()
+{
+ Q_D(QQmlDelegateModel);
+ d->setColumns(-1);
+}
+
+/*!
\qmlmethod QModelIndex QtQml.Models::DelegateModel::modelIndex(int index)
QAbstractItemModel provides a hierarchical tree of data, whereas
@@ -1045,7 +1164,10 @@ QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index)
if (!it->inCache())
return QQmlIncubator::Null;
- return d->m_cache.at(it.cacheIndex)->incubationTask->status();
+ if (auto incubationTask = d->m_cache.at(it.cacheIndex)->incubationTask)
+ return incubationTask->status();
+
+ return QQmlIncubator::Ready;
}
QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
@@ -3193,7 +3315,10 @@ QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index)
if (!it->inCache())
return QQmlIncubator::Null;
- return model->m_cache.at(it.cacheIndex)->incubationTask->status();
+ if (auto incubationTask = model->m_cache.at(it.cacheIndex)->incubationTask)
+ return incubationTask->status();
+
+ return QQmlIncubator::Ready;
}
int QQmlPartsModel::indexOf(QObject *item, QObject *) const
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index b894df8f82..439d5c9d37 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -86,6 +86,8 @@ class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public
Q_PROPERTY(QQmlListProperty<QQmlDelegateModelGroup> groups READ groups CONSTANT)
Q_PROPERTY(QObject *parts READ parts CONSTANT)
Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
+ Q_PROPERTY(int rows READ rows WRITE setRows RESET resetRows NOTIFY rowsChanged REVISION 12)
+ Q_PROPERTY(int columns READ columns WRITE setColumns RESET resetColumns NOTIFY columnsChanged REVISION 12)
Q_CLASSINFO("DefaultProperty", "delegate")
Q_INTERFACES(QQmlParserStatus)
public:
@@ -105,6 +107,14 @@ public:
QVariant rootIndex() const;
void setRootIndex(const QVariant &root);
+ int rows() const;
+ void setRows(int rows);
+ void resetRows();
+
+ int columns() const;
+ void setColumns(int columns);
+ void resetColumns();
+
Q_INVOKABLE QVariant modelIndex(int idx) const;
Q_INVOKABLE QVariant parentModelIndex() const;
@@ -136,6 +146,8 @@ Q_SIGNALS:
void filterGroupChanged();
void defaultGroupsChanged();
void rootIndexChanged();
+ Q_REVISION(12) void rowsChanged();
+ Q_REVISION(12) void columnsChanged();
private Q_SLOTS:
void _q_itemsChanged(int index, int count, const QVector<int> &roles);
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 68b987a5fa..9f1c9d31a4 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -119,7 +119,7 @@ public:
int groupIndex(Compositor::Group group);
int modelIndex() const { return index; }
- void setModelIndex(int idx) { index = idx; Q_EMIT modelIndexChanged(); }
+ virtual void setModelIndex(int idx) { index = idx; Q_EMIT modelIndexChanged(); }
virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(v4, this); }
@@ -301,6 +301,9 @@ public:
void incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status);
void setInitialState(QQDMIncubationTask *incubationTask, QObject *o);
+ void setRows(int rows);
+ void setColumns(int columns);
+
QQmlAdaptorModel m_adaptorModel;
QQmlListCompositor m_compositor;
QQmlComponent *m_delegate;
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 0c0859dc80..0a9d29ac05 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -64,6 +64,8 @@
#include <private/qv4engine_p.h>
#include <private/qpodvector_p.h>
+QT_REQUIRE_CONFIG(qml_list_model);
+
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index ad5e94c909..99e9b30aff 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -57,6 +57,8 @@
#include <private/qv4qobjectwrapper_p.h>
#include <qqml.h>
+QT_REQUIRE_CONFIG(qml_list_model);
+
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h
index 2120f25744..ae2d4b11e0 100644
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ b/src/qml/types/qqmllistmodelworkeragent_p.h
@@ -59,6 +59,8 @@
#include <private/qv8engine_p.h>
+QT_REQUIRE_CONFIG(qml_list_model);
+
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
index c36e26a525..872d7c059f 100644
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ b/src/qml/types/qqmlmodelsmodule.cpp
@@ -39,7 +39,9 @@
#include "qqmlmodelsmodule_p.h"
#include <QtCore/qitemselectionmodel.h>
+#if QT_CONFIG(qml_list_model)
#include <private/qqmllistmodel_p.h>
+#endif
#include <private/qqmldelegatemodel_p.h>
#include <private/qqmlobjectmodel_p.h>
@@ -49,9 +51,12 @@ void QQmlModelsModule::defineModule()
{
const char uri[] = "QtQml.Models";
+#if QT_CONFIG(qml_list_model)
qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
+#endif
qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
+ qmlRegisterType<QQmlDelegateModel,12>(uri, 2, 9, "DelegateModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index d597869994..0160e97a2f 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -57,6 +57,8 @@
#include <private/qtqmlglobal_p.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class QQmlTimerPrivate;
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 80c2d3a4bc..dbc2769dd1 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -37,9 +37,12 @@
**
****************************************************************************/
+#include "qtqmlglobal_p.h"
#include "qquickworkerscript_p.h"
+#if QT_CONFIG(qml_list_model)
#include "qqmllistmodel_p.h"
#include "qqmllistmodelworkeragent_p.h"
+#endif
#include <private/qqmlengine_p.h>
#include <private/qqmlexpression_p.h>
@@ -201,7 +204,7 @@ private:
};
QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent)
- : QV8Engine(nullptr, new QV4::ExecutionEngine), p(parent)
+ : QV8Engine(new QV4::ExecutionEngine), p(parent)
#if QT_CONFIG(qml_network)
, accessManager(nullptr)
#endif
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index e85ab5982b..25b231f954 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -2,8 +2,6 @@ SOURCES += \
$$PWD/qqmlbind.cpp \
$$PWD/qqmlconnections.cpp \
$$PWD/qqmldelegatemodel.cpp \
- $$PWD/qqmllistmodel.cpp \
- $$PWD/qqmllistmodelworkeragent.cpp \
$$PWD/qqmlmodelsmodule.cpp \
$$PWD/qqmlmodelindexvaluetype.cpp \
$$PWD/qqmlobjectmodel.cpp \
@@ -16,9 +14,6 @@ HEADERS += \
$$PWD/qqmlconnections_p.h \
$$PWD/qqmldelegatemodel_p.h \
$$PWD/qqmldelegatemodel_p_p.h \
- $$PWD/qqmllistmodel_p.h \
- $$PWD/qqmllistmodel_p_p.h \
- $$PWD/qqmllistmodelworkeragent_p.h \
$$PWD/qqmlmodelsmodule_p.h \
$$PWD/qqmlmodelindexvaluetype_p.h \
$$PWD/qqmlobjectmodel_p.h \
@@ -27,7 +22,18 @@ HEADERS += \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_p.h
-qtConfig(animation) {
+qtConfig(qml-list-model) {
+ SOURCES += \
+ $$PWD/qqmllistmodel.cpp \
+ $$PWD/qqmllistmodelworkeragent.cpp
+
+ HEADERS += \
+ $$PWD/qqmllistmodel_p.h \
+ $$PWD/qqmllistmodel_p_p.h \
+ $$PWD/qqmllistmodelworkeragent_p.h
+}
+
+qtConfig(qml-animation) {
SOURCES += \
$$PWD/qqmltimer.cpp
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index b4bebb9d5d..1cc347d6bc 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -330,9 +330,8 @@ bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &, int idx)
{
if (index == -1) {
Q_ASSERT(idx >= 0);
- index = idx;
cachedData.clear();
- emit modelIndexChanged();
+ setModelIndex(idx);
const QMetaObject *meta = metaObject();
const int propertyCount = type->propertyRoles.count();
for (int i = 0; i < propertyCount; ++i)
@@ -399,13 +398,18 @@ QV4::ReturnedValue QQmlDMCachedModelData::set_property(const QV4::FunctionObject
class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData
{
Q_OBJECT
+ Q_PROPERTY(int row MEMBER row NOTIFY rowChanged)
+ Q_PROPERTY(int column MEMBER column NOTIFY columnChanged)
Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
+
public:
QQmlDMAbstractItemModelData(
QQmlDelegateModelItemMetaType *metaType,
VDMModelDelegateDataType *dataType,
int index)
: QQmlDMCachedModelData(metaType, dataType, index)
+ , row(type->model->rowAt(index))
+ , column(type->model->columnAt(index))
{
}
@@ -413,7 +417,7 @@ public:
{
if (index >= 0 && *type->model) {
const QAbstractItemModel * const model = type->model->aim();
- return model->hasChildren(model->index(index, 0, type->model->rootIndex));
+ return model->hasChildren(model->index(row, column, type->model->rootIndex));
} else {
return false;
}
@@ -421,13 +425,13 @@ public:
QVariant value(int role) const override
{
- return type->model->aim()->index(index, 0, type->model->rootIndex).data(role);
+ return type->model->aim()->index(row, column, type->model->rootIndex).data(role);
}
void setValue(int role, const QVariant &value) override
{
type->model->aim()->setData(
- type->model->aim()->index(index, 0, type->model->rootIndex), value, role);
+ type->model->aim()->index(row, column, type->model->rootIndex), value, role);
}
QV4::ReturnedValue get() override
@@ -443,6 +447,16 @@ public:
++scriptRef;
return o.asReturnedValue();
}
+
+ void setModelIndex(int idx) override;
+
+Q_SIGNALS:
+ void rowChanged();
+ void columnChanged();
+
+private:
+ int row;
+ int column;
};
class VDMAbstractItemModelDataType : public VDMModelDelegateDataType
@@ -453,11 +467,16 @@ public:
{
}
- int count(const QQmlAdaptorModel &model) const override
+ int rowCount(const QQmlAdaptorModel &model) const override
{
return model.aim()->rowCount(model.rootIndex);
}
+ int columnCount(const QQmlAdaptorModel &model) const override
+ {
+ return model.aim()->columnCount(model.rootIndex);
+ }
+
void cleanup(QQmlAdaptorModel &model, QQmlDelegateModel *vdm) const override
{
QAbstractItemModel * const aim = model.aim();
@@ -485,9 +504,9 @@ public:
{
QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
if (it != roleNames.end()) {
- return model.aim()->index(index, 0, model.rootIndex).data(*it);
+ return model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex).data(*it);
} else if (role == QLatin1String("hasModelChildren")) {
- return QVariant(model.aim()->hasChildren(model.aim()->index(index, 0, model.rootIndex)));
+ return QVariant(model.aim()->hasChildren(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex)));
} else {
return QVariant();
}
@@ -503,7 +522,7 @@ public:
QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
{
return model
- ? QVariant::fromValue(model.aim()->index(index, 0, model.rootIndex))
+ ? QVariant::fromValue(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex))
: QVariant();
}
@@ -558,6 +577,22 @@ public:
}
};
+void QQmlDMAbstractItemModelData::setModelIndex(int idx)
+{
+ QQmlDMCachedModelData::setModelIndex(idx);
+
+ int prevRow = row;
+ int prevColumn = column;
+
+ row = type->model->rowAt(idx);
+ column = type->model->columnAt(idx);
+
+ if (row != prevRow)
+ emit rowChanged();
+ if (column != prevColumn)
+ emit columnChanged();
+}
+
//-----------------------------------------------------------------
// QQmlListAccessor
//-----------------------------------------------------------------
@@ -653,11 +688,16 @@ class VDMListDelegateDataType : public QQmlAdaptorModel::Accessors
public:
inline VDMListDelegateDataType() {}
- int count(const QQmlAdaptorModel &model) const override
+ int rowCount(const QQmlAdaptorModel &model) const override
{
return model.list.count();
}
+ int columnCount(const QQmlAdaptorModel &) const override
+ {
+ return 1;
+ }
+
QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
return role == QLatin1String("modelData")
@@ -737,11 +777,16 @@ public:
free(metaObject);
}
- int count(const QQmlAdaptorModel &model) const override
+ int rowCount(const QQmlAdaptorModel &model) const override
{
return model.list.count();
}
+ int columnCount(const QQmlAdaptorModel &) const override
+ {
+ return 1;
+ }
+
QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
if (QObject *object = model.list.at(index).value<QObject *>())
@@ -955,7 +1000,38 @@ void QQmlAdaptorModel::invalidateModel(QQmlDelegateModel *vdm)
bool QQmlAdaptorModel::isValid() const
{
- return accessors != &qt_vdm_null_accessors;
+ return accessors != &qt_vdm_null_accessors || rows.isValid();
+}
+
+int QQmlAdaptorModel::count() const
+{
+ return rowCount() * columnCount();
+}
+
+int QQmlAdaptorModel::rowCount() const
+{
+ if (rows.isValid())
+ return rows.value;
+ return qMax(0, accessors->rowCount(*this));
+}
+
+int QQmlAdaptorModel::columnCount() const
+{
+ if (columns.isValid())
+ return columns.value;
+ return qMax(isValid() ? 1 : 0, accessors->columnCount(*this));
+}
+
+int QQmlAdaptorModel::rowAt(int index) const
+{
+ int count = rowCount();
+ return count <= 0 ? -1 : index % count;
+}
+
+int QQmlAdaptorModel::columnAt(int index) const
+{
+ int count = rowCount();
+ return count <= 0 ? -1 : index / count;
}
void QQmlAdaptorModel::objectDestroyed(QObject *)
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h
index 8f773efa20..f0d3bcd186 100644
--- a/src/qml/util/qqmladaptormodel_p.h
+++ b/src/qml/util/qqmladaptormodel_p.h
@@ -56,6 +56,7 @@
#include "private/qqmllistaccessor_p.h"
#include <private/qqmlguard_p.h>
+#include <private/qqmlnullablevalue_p.h>
QT_BEGIN_NAMESPACE
@@ -73,7 +74,8 @@ public:
public:
inline Accessors() {}
virtual ~Accessors();
- virtual int count(const QQmlAdaptorModel &) const { return 0; }
+ virtual int rowCount(const QQmlAdaptorModel &) const { return 0; }
+ virtual int columnCount(const QQmlAdaptorModel &) const { return 0; }
virtual void cleanup(QQmlAdaptorModel &, QQmlDelegateModel * = nullptr) const {}
virtual QVariant value(const QQmlAdaptorModel &, int, const QString &) const {
@@ -102,6 +104,8 @@ public:
virtual void fetchMore(QQmlAdaptorModel &) const {}
};
+ QQmlNullableValue<int> rows;
+ QQmlNullableValue<int> columns;
const Accessors *accessors;
QPersistentModelIndex rootIndex;
QQmlListAccessor list;
@@ -114,11 +118,15 @@ public:
void invalidateModel(QQmlDelegateModel *vdm);
bool isValid() const;
+ int count() const;
+ int rowCount() const;
+ int columnCount() const;
+ int rowAt(int index) const;
+ int columnAt(int index) const;
inline QAbstractItemModel *aim() { return static_cast<QAbstractItemModel *>(object()); }
inline const QAbstractItemModel *aim() const { return static_cast<const QAbstractItemModel *>(object()); }
- inline int count() const { return qMax(0, accessors->count(*this)); }
inline QVariant value(int index, const QString &role) const {
return accessors->value(*this, index, role); }
inline QQmlDelegateModelItem *createItem(QQmlDelegateModelItemMetaType *metaType, int index) {