aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-07-09 09:25:40 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-07-11 09:42:52 +0200
commitbe600348ef3530ba69290cb1610d673faafae866 (patch)
tree7530b1b109894ee819ec2b8584ad8365c4653534 /src/qml/qml
parent9a8dd594b5f953d385d69b1ea0d74939f69b4728 (diff)
Split qqmltypeloader{_p.h|.cpp} into a several files
No one can read this mess. Change-Id: Icec4f2afc466435c1ae5e4e80fa2c1b5baf7d087 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qml.pri22
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp1
-rw-r--r--src/qml/qml/qqmlbinding.cpp1
-rw-r--r--src/qml/qml/qqmlbinding_p.h1
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp1
-rw-r--r--src/qml/qml/qqmldatablob.cpp639
-rw-r--r--src/qml/qml/qqmldatablob_p.h257
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp1
-rw-r--r--src/qml/qml/qqmldirdata.cpp96
-rw-r--r--src/qml/qml/qqmldirdata_p.h86
-rw-r--r--src/qml/qml/qqmlengine.cpp11
-rw-r--r--src/qml/qml/qqmlengine_p.h1
-rw-r--r--src/qml/qml/qqmlexpression.cpp1
-rw-r--r--src/qml/qml/qqmlimport.cpp1
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp1
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h1
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h1
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp263
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h97
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp170
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h108
-rw-r--r--src/qml/qml/qqmltypedata.cpp842
-rw-r--r--src/qml/qml/qqmltypedata_p.h163
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2198
-rw-r--r--src/qml/qml/qqmltypeloader_p.h408
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp74
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h86
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp115
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h94
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp198
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h110
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp1
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp1
34 files changed, 3478 insertions, 2573 deletions
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 15ea12cbe7..660a883e63 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -1,7 +1,14 @@
SOURCES += \
$$PWD/qqml.cpp \
+ $$PWD/qqmldatablob.cpp \
+ $$PWD/qqmldirdata.cpp \
$$PWD/qqmlerror.cpp \
$$PWD/qqmlopenmetaobject.cpp \
+ $$PWD/qqmlscriptblob.cpp \
+ $$PWD/qqmlscriptdata.cpp \
+ $$PWD/qqmltypedata.cpp \
+ $$PWD/qqmltypeloaderqmldircontent.cpp \
+ $$PWD/qqmltypeloaderthread.cpp \
$$PWD/qqmlvmemetaobject.cpp \
$$PWD/qqmlengine.cpp \
$$PWD/qqmlexpression.cpp \
@@ -61,8 +68,15 @@ SOURCES += \
$$PWD/qqmlpropertyvalidator.cpp
HEADERS += \
+ $$PWD/qqmldatablob_p.h \
+ $$PWD/qqmldirdata_p.h \
$$PWD/qqmlglobal_p.h \
$$PWD/qqmlopenmetaobject_p.h \
+ $$PWD/qqmlscriptblob_p.h \
+ $$PWD/qqmlscriptdata_p.h \
+ $$PWD/qqmltypedata_p.h \
+ $$PWD/qqmltypeloaderqmldircontent_p.h \
+ $$PWD/qqmltypeloaderthread_p.h \
$$PWD/qqmlvmemetaobject_p.h \
$$PWD/qqml.h \
$$PWD/qqmlproperty.h \
@@ -163,5 +177,13 @@ qtConfig(qml-locale) {
$$PWD/qqmllocale.cpp
}
+qtConfig(qml-network) {
+ HEADERS += \
+ $$PWD/qqmltypeloadernetworkreplyproxy_p.h
+
+ SOURCES += \
+ $$PWD/qqmltypeloadernetworkreplyproxy.cpp
+}
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 7149f8c134..e93cfcadb9 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include <QtQml/qqmlfile.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QTranslator>
#include <QQmlComponent>
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 7fb15af570..3a437eab8d 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -49,6 +49,7 @@
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 85b02dcde4..7f96b4df9f 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -63,6 +63,7 @@
#include <private/qqmlabstractbinding_p.h>
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index dc973630a7..ff01e737ca 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -56,6 +56,7 @@
#include <private/qv4value_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
new file mode 100644
index 0000000000..2183721d32
--- /dev/null
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -0,0 +1,639 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmldatablob_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlprofiler_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#include <QtQml/qqmlengine.h>
+
+#ifdef DATABLOB_DEBUG
+#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
+#else
+#define ASSERT_CALLBACK()
+#endif
+
+DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QQmlDataBlob
+\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
+\internal
+
+QQmlDataBlob's are loaded by a QQmlTypeLoader. The user creates the QQmlDataBlob
+and then calls QQmlTypeLoader::load() or QQmlTypeLoader::loadWithStaticData() to load it.
+The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes available.
+*/
+
+/*!
+\enum QQmlDataBlob::Status
+
+This enum describes the status of the data blob.
+
+\list
+\li Null The blob has not yet been loaded by a QQmlTypeLoader
+\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
+ invoked or has not yet returned.
+\li WaitingForDependencies The blob is waiting for dependencies to be done before continuing.
+ This status only occurs after the QQmlDataBlob::setData() callback has been made, and when the
+ blob has outstanding dependencies.
+\li Complete The blob's data has been loaded and all dependencies are done.
+\li Error An error has been set on this blob.
+\endlist
+*/
+
+/*!
+\enum QQmlDataBlob::Type
+
+This enum describes the type of the data blob.
+
+\list
+\li QmlFile This is a QQmlTypeData
+\li JavaScriptFile This is a QQmlScriptData
+\li QmldirFile This is a QQmlQmldirData
+\endlist
+*/
+
+/*!
+Create a new QQmlDataBlob for \a url and of the provided \a type.
+*/
+QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
+: m_typeLoader(manager), m_type(type), m_url(url), m_finalUrl(url), m_redirectCount(0),
+ m_inCallback(false), m_isDone(false)
+{
+ //Set here because we need to get the engine from the manager
+ if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
+ m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
+ (QQmlAbstractUrlInterceptor::DataType)m_type);
+}
+
+/*! \internal */
+QQmlDataBlob::~QQmlDataBlob()
+{
+ Q_ASSERT(m_waitingOnMe.isEmpty());
+
+ cancelAllWaitingFor();
+}
+
+/*!
+ Must be called before loading can occur.
+*/
+void QQmlDataBlob::startLoading()
+{
+ Q_ASSERT(status() == QQmlDataBlob::Null);
+ m_data.setStatus(QQmlDataBlob::Loading);
+}
+
+/*!
+Returns the type provided to the constructor.
+*/
+QQmlDataBlob::Type QQmlDataBlob::type() const
+{
+ return m_type;
+}
+
+/*!
+Returns the blob's status.
+*/
+QQmlDataBlob::Status QQmlDataBlob::status() const
+{
+ return m_data.status();
+}
+
+/*!
+Returns true if the status is Null.
+*/
+bool QQmlDataBlob::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+Returns true if the status is Loading.
+*/
+bool QQmlDataBlob::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+Returns true if the status is WaitingForDependencies.
+*/
+bool QQmlDataBlob::isWaiting() const
+{
+ return status() == WaitingForDependencies ||
+ status() == ResolvingDependencies;
+}
+
+/*!
+Returns true if the status is Complete.
+*/
+bool QQmlDataBlob::isComplete() const
+{
+ return status() == Complete;
+}
+
+/*!
+Returns true if the status is Error.
+*/
+bool QQmlDataBlob::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+Returns true if the status is Complete or Error.
+*/
+bool QQmlDataBlob::isCompleteOrError() const
+{
+ Status s = status();
+ return s == Error || s == Complete;
+}
+
+/*!
+Returns the data download progress from 0 to 1.
+*/
+qreal QQmlDataBlob::progress() const
+{
+ quint8 p = m_data.progress();
+ if (p == 0xFF) return 1.;
+ else return qreal(p) / qreal(0xFF);
+}
+
+/*!
+Returns the physical url of the data. Initially this is the same as
+finalUrl(), but if a URL interceptor is set, it will work on this URL
+and leave finalUrl() alone.
+
+\sa finalUrl()
+*/
+QUrl QQmlDataBlob::url() const
+{
+ return m_url;
+}
+
+QString QQmlDataBlob::urlString() const
+{
+ if (m_urlString.isEmpty())
+ m_urlString = m_url.toString();
+
+ return m_urlString;
+}
+
+/*!
+Returns the logical URL to be used for resolving further URLs referred to in
+the code.
+
+This is the blob url passed to the constructor. If a URL interceptor rewrites
+the URL, this one stays the same. If a network redirect happens while fetching
+the data, this url is updated to reflect the new location. Therefore, if both
+an interception and a redirection happen, the final url will indirectly
+incorporate the result of the interception, potentially breaking further
+lookups.
+
+\sa url()
+*/
+QUrl QQmlDataBlob::finalUrl() const
+{
+ return m_finalUrl;
+}
+
+/*!
+Returns the finalUrl() as a string.
+*/
+QString QQmlDataBlob::finalUrlString() const
+{
+ if (m_finalUrlString.isEmpty())
+ m_finalUrlString = m_finalUrl.toString();
+
+ return m_finalUrlString;
+}
+
+/*!
+Return the errors on this blob.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
+*/
+QList<QQmlError> QQmlDataBlob::errors() const
+{
+ Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
+ return m_errors;
+}
+
+/*!
+Mark this blob as having \a errors.
+
+All outstanding dependencies will be cancelled. Requests to add new dependencies
+will be ignored. Entry into the Error state is irreversable.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::setError(const QQmlError &errors)
+{
+ ASSERT_CALLBACK();
+
+ QList<QQmlError> l;
+ l << errors;
+ setError(l);
+}
+
+/*!
+\overload
+*/
+void QQmlDataBlob::setError(const QList<QQmlError> &errors)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Error);
+ Q_ASSERT(m_errors.isEmpty());
+
+ m_errors = errors; // Must be set before the m_data fence
+ m_data.setStatus(Error);
+
+ if (dumpErrors()) {
+ qWarning().nospace() << "Errors for " << urlString();
+ for (int ii = 0; ii < errors.count(); ++ii)
+ qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
+ }
+ cancelAllWaitingFor();
+
+ if (!m_inCallback)
+ tryDone();
+}
+
+void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
+{
+ QQmlError e;
+ e.setColumn(error.column);
+ e.setLine(error.line);
+ e.setDescription(error.message);
+ e.setUrl(url());
+ setError(e);
+}
+
+void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors)
+{
+ QList<QQmlError> finalErrors;
+ finalErrors.reserve(errors.count());
+ for (const auto &error : errors) {
+ QQmlError e;
+ e.setColumn(error.column);
+ e.setLine(error.line);
+ e.setDescription(error.message);
+ e.setUrl(url());
+ finalErrors << e;
+ }
+ setError(finalErrors);
+}
+
+void QQmlDataBlob::setError(const QString &description)
+{
+ QQmlError e;
+ e.setDescription(description);
+ e.setUrl(url());
+ setError(e);
+}
+
+/*!
+Wait for \a blob to become complete or to error. If \a blob is already
+complete or in error, or this blob is already complete, this has no effect.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Null);
+
+ if (!blob ||
+ blob->status() == Error || blob->status() == Complete ||
+ status() == Error || status() == Complete || m_isDone)
+ return;
+
+ for (auto existingDep: qAsConst(m_waitingFor))
+ if (existingDep.data() == blob)
+ return;
+
+ m_data.setStatus(WaitingForDependencies);
+
+ m_waitingFor.append(blob);
+ blob->m_waitingOnMe.append(this);
+}
+
+/*!
+\fn void QQmlDataBlob::dataReceived(const Data &data)
+
+Invoked when data for the blob is received. Implementors should use this callback
+to determine a blob's dependencies. Within this callback you may call setError()
+or addDependency().
+*/
+
+/*!
+Invoked once data has either been received or a network error occurred, and all
+dependencies are complete.
+
+You can set an error in this method, but you cannot add new dependencies. Implementors
+should use this callback to finalize processing of data.
+
+The default implementation does nothing.
+
+XXX Rename processData() or some such to avoid confusion between done() (processing thread)
+and completed() (main thread)
+*/
+void QQmlDataBlob::done()
+{
+}
+
+#if QT_CONFIG(qml_network)
+/*!
+Invoked if there is a network error while fetching this blob.
+
+The default implementation sets an appropriate QQmlError.
+*/
+void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
+{
+ Q_UNUSED(networkError);
+
+ QQmlError error;
+ error.setUrl(m_url);
+
+ const char *errorString = nullptr;
+ switch (networkError) {
+ default:
+ errorString = "Network error";
+ break;
+ case QNetworkReply::ConnectionRefusedError:
+ errorString = "Connection refused";
+ break;
+ case QNetworkReply::RemoteHostClosedError:
+ errorString = "Remote host closed the connection";
+ break;
+ case QNetworkReply::HostNotFoundError:
+ errorString = "Host not found";
+ break;
+ case QNetworkReply::TimeoutError:
+ errorString = "Timeout";
+ break;
+ case QNetworkReply::ProxyConnectionRefusedError:
+ case QNetworkReply::ProxyConnectionClosedError:
+ case QNetworkReply::ProxyNotFoundError:
+ case QNetworkReply::ProxyTimeoutError:
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ case QNetworkReply::UnknownProxyError:
+ errorString = "Proxy error";
+ break;
+ case QNetworkReply::ContentAccessDenied:
+ errorString = "Access denied";
+ break;
+ case QNetworkReply::ContentNotFoundError:
+ errorString = "File not found";
+ break;
+ case QNetworkReply::AuthenticationRequiredError:
+ errorString = "Authentication required";
+ break;
+ };
+
+ error.setDescription(QLatin1String(errorString));
+
+ setError(error);
+}
+#endif // qml_network
+
+/*!
+Called if \a blob, which was previously waited for, has an error.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has completed.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called when all blobs waited for have completed. This occurs regardless of
+whether they are in error, or complete state.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::allDependenciesDone()
+{
+ m_data.setStatus(QQmlDataBlob::ResolvingDependencies);
+}
+
+/*!
+Called when the download progress of this blob changes. \a progress goes
+from 0 to 1.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::downloadProgressChanged(qreal progress)
+{
+ Q_UNUSED(progress);
+}
+
+/*!
+Invoked on the main thread sometime after done() was called on the load thread.
+
+You cannot modify the blobs state at all in this callback and cannot depend on the
+order or timeliness of these callbacks. Implementors should use this callback to notify
+dependencies on the main thread that the blob is done and not a lot else.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::completed()
+{
+}
+
+
+void QQmlDataBlob::tryDone()
+{
+ if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
+ m_isDone = true;
+ addref();
+
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
+#endif
+ done();
+
+ if (status() != Error)
+ m_data.setStatus(Complete);
+
+ notifyAllWaitingOnMe();
+
+ // Locking is not required here, as anyone expecting callbacks must
+ // already be protected against the blob being completed (as set above);
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob: Dispatching completed");
+#endif
+ m_typeLoader->m_thread->callCompleted(this);
+
+ release();
+ }
+}
+
+void QQmlDataBlob::cancelAllWaitingFor()
+{
+ while (m_waitingFor.count()) {
+ QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
+
+ Q_ASSERT(blob->m_waitingOnMe.contains(this));
+
+ blob->m_waitingOnMe.removeOne(this);
+ }
+}
+
+void QQmlDataBlob::notifyAllWaitingOnMe()
+{
+ while (m_waitingOnMe.count()) {
+ QQmlDataBlob *blob = m_waitingOnMe.takeLast();
+
+ Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
+ [this](const QQmlRefPointer<QQmlDataBlob> &waiting) { return waiting.data() == this; }));
+
+ blob->notifyComplete(this);
+ }
+}
+
+void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
+{
+ Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+ QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
+
+ m_inCallback = true;
+
+ QQmlRefPointer<QQmlDataBlob> blobRef;
+ for (int i = 0; i < m_waitingFor.count(); ++i) {
+ if (m_waitingFor.at(i).data() == blob) {
+ blobRef = m_waitingFor.takeAt(i);
+ break;
+ }
+ }
+ Q_ASSERT(blobRef);
+
+ if (blob->status() == Error) {
+ dependencyError(blob);
+ } else if (blob->status() == Complete) {
+ dependencyComplete(blob);
+ }
+
+ if (!isError() && m_waitingFor.isEmpty())
+ allDependenciesDone();
+
+ m_inCallback = false;
+
+ tryDone();
+}
+
+QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
+{
+ error->clear();
+ if (hasInlineSourceCode)
+ return inlineSourceCode;
+
+ QFile f(fileInfo.absoluteFilePath());
+ if (!f.open(QIODevice::ReadOnly)) {
+ *error = f.errorString();
+ return QString();
+ }
+
+ const qint64 fileSize = fileInfo.size();
+
+ if (uchar *mappedData = f.map(0, fileSize)) {
+ QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
+ f.unmap(mappedData);
+ return source;
+ }
+
+ QByteArray data(fileSize, Qt::Uninitialized);
+ if (f.read(data.data(), data.length()) != data.length()) {
+ *error = f.errorString();
+ return QString();
+ }
+ return QString::fromUtf8(data);
+}
+
+QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
+{
+ if (hasInlineSourceCode)
+ return QDateTime();
+
+ return fileInfo.lastModified();
+}
+
+bool QQmlDataBlob::SourceCodeData::exists() const
+{
+ if (hasInlineSourceCode)
+ return true;
+ return fileInfo.exists();
+}
+
+bool QQmlDataBlob::SourceCodeData::isEmpty() const
+{
+ if (hasInlineSourceCode)
+ return inlineSourceCode.isEmpty();
+ return fileInfo.size() == 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h
new file mode 100644
index 0000000000..da3bbe2c1f
--- /dev/null
+++ b/src/qml/qml/qqmldatablob_p.h
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDATABLOB_P_H
+#define QQMLDATABLOB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qv4compileddata_p.h>
+
+#if QT_CONFIG(qml_network)
+#include <QtNetwork/qnetworkreply.h>
+#endif
+
+#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeLoader;
+class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
+{
+public:
+ enum Status {
+ Null, // Prior to QQmlTypeLoader::load()
+ Loading, // Prior to data being received and dataReceived() being called
+ WaitingForDependencies, // While there are outstanding addDependency()s
+ ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
+ Complete, // Finished
+ Error // Error
+ };
+
+ enum Type { //Matched in QQmlAbstractUrlInterceptor
+ QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
+ JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
+ QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
+ };
+
+ QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
+ ~QQmlDataBlob() override;
+
+ void startLoading();
+
+ QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
+
+ Type type() const;
+
+ Status status() const;
+ bool isNull() const;
+ bool isLoading() const;
+ bool isWaiting() const;
+ bool isComplete() const;
+ bool isError() const;
+ bool isCompleteOrError() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+ QString urlString() const;
+ QUrl finalUrl() const;
+ QString finalUrlString() const;
+
+ QList<QQmlError> errors() const;
+
+ class SourceCodeData {
+ public:
+ QString readAll(QString *error) const;
+ QDateTime sourceTimeStamp() const;
+ bool exists() const;
+ bool isEmpty() const;
+ private:
+ friend class QQmlDataBlob;
+ friend class QQmlTypeLoader;
+ QString inlineSourceCode;
+ QFileInfo fileInfo;
+ bool hasInlineSourceCode = false;
+ };
+
+protected:
+ // Can be called from within callbacks
+ void setError(const QQmlError &);
+ void setError(const QList<QQmlError> &errors);
+ void setError(const QQmlJS::DiagnosticMessage &error);
+ void setError(const QVector<QQmlJS::DiagnosticMessage> &errors);
+ void setError(const QString &description);
+ void addDependency(QQmlDataBlob *);
+
+ // Callbacks made in load thread
+ virtual void dataReceived(const SourceCodeData &) = 0;
+ virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
+ virtual void done();
+#if QT_CONFIG(qml_network)
+ virtual void networkError(QNetworkReply::NetworkError);
+#endif
+ virtual void dependencyError(QQmlDataBlob *);
+ virtual void dependencyComplete(QQmlDataBlob *);
+ virtual void allDependenciesDone();
+
+ // Callbacks made in main thread
+ virtual void downloadProgressChanged(qreal);
+ virtual void completed();
+
+protected:
+ // Manager that is currently fetching data for me
+ QQmlTypeLoader *m_typeLoader;
+
+private:
+ friend class QQmlTypeLoader;
+ friend class QQmlTypeLoaderThread;
+
+ void tryDone();
+ void cancelAllWaitingFor();
+ void notifyAllWaitingOnMe();
+ void notifyComplete(QQmlDataBlob *);
+
+ struct ThreadData {
+ private:
+ enum {
+ StatusMask = 0x0000FFFF,
+ StatusShift = 0,
+ ProgressMask = 0x00FF0000,
+ ProgressShift = 16,
+ AsyncMask = 0x80000000,
+ NoMask = 0
+ };
+
+ public:
+ inline ThreadData()
+ : _p(0)
+ {
+ }
+
+ inline QQmlDataBlob::Status status() const
+ {
+ return QQmlDataBlob::Status((_p.loadRelaxed() & StatusMask) >> StatusShift);
+ }
+
+ inline void setStatus(QQmlDataBlob::Status status)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ inline bool isAsync() const
+ {
+ return _p.loadRelaxed() & AsyncMask;
+ }
+
+ inline void setIsAsync(bool v)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ inline quint8 progress() const
+ {
+ return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift);
+ }
+
+ inline void setProgress(quint8 v)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ private:
+ QAtomicInt _p;
+ };
+ ThreadData m_data;
+
+ // m_errors should *always* be written before the status is set to Error.
+ // We use the status change as a memory fence around m_errors so that locking
+ // isn't required. Once the status is set to Error (or Complete), m_errors
+ // cannot be changed.
+ QList<QQmlError> m_errors;
+
+ Type m_type;
+
+ QUrl m_url;
+ QUrl m_finalUrl;
+ mutable QString m_urlString;
+ mutable QString m_finalUrlString;
+
+ // List of QQmlDataBlob's that are waiting for me to complete.
+ QList<QQmlDataBlob *> m_waitingOnMe;
+
+ // List of QQmlDataBlob's that I am waiting for to complete.
+ QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
+
+ int m_redirectCount:30;
+ bool m_inCallback:1;
+ bool m_isDone:1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDATABLOB_P_H
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 857b5be8b8..02fde97b3d 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -43,6 +43,7 @@
#include <private/qv4value_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QQmlError>
diff --git a/src/qml/qml/qqmldirdata.cpp b/src/qml/qml/qqmldirdata.cpp
new file mode 100644
index 0000000000..ec398fa896
--- /dev/null
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmldirdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
+ : QQmlTypeLoader::Blob(url, QmldirFile, loader)
+{
+}
+
+const QString &QQmlQmldirData::content() const
+{
+ return m_content;
+}
+
+const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
+{
+ QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *>::const_iterator it =
+ m_imports.find(blob);
+ if (it == m_imports.end())
+ return nullptr;
+ return *it;
+}
+
+void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
+{
+ m_imports[blob] = import;
+}
+
+int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
+{
+ QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
+ if (it == m_priorities.end())
+ return 0;
+ return *it;
+}
+
+void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
+{
+ m_priorities[blob] = priority;
+}
+
+void QQmlQmldirData::dataReceived(const SourceCodeData &data)
+{
+ QString error;
+ m_content = data.readAll(&error);
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+}
+
+void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
+{
+ Q_UNIMPLEMENTED();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldirdata_p.h b/src/qml/qml/qqmldirdata_p.h
new file mode 100644
index 0000000000..6af393c47f
--- /dev/null
+++ b/src/qml/qml/qqmldirdata_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDIRDATA_P_H
+#define QQMLDIRDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
+
+public:
+ const QString &content() const;
+
+ const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const;
+ void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *);
+
+ int priority(QQmlTypeLoader::Blob *) const;
+ void setPriority(QQmlTypeLoader::Blob *, int);
+
+protected:
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
+
+private:
+ QString m_content;
+ QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *> m_imports;
+ QHash<QQmlTypeLoader::Blob *, int> m_priorities;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDIRDATA_P_H
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index e726e0810d..f5a9e6aac4 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -2325,6 +2325,17 @@ QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName)
return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
}
+// #### Qt 6: Remove this function, it exists only for binary compatibility.
+/*!
+ * \internal
+ */
+bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
+{
+ Q_UNUSED(name)
+ Q_UNUSED(fileName)
+ return false;
+}
+
QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
{
Q_Q(const QQmlEngine);
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index e58ff554a7..385ae02ce5 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -66,6 +66,7 @@
#include <private/qintrusivelist_p.h>
#include <private/qrecyclepool_p.h>
#include <private/qfieldlist_p.h>
+#include <private/qv4engine_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index be0adc54a7..f6a5afb891 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -46,6 +46,7 @@
#include "qqmlscriptstring_p.h"
#include "qqmlbinding_p.h"
#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 95ab79070d..f4cdb45aff 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
#include <private/qqmltypemodule_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 67fdf8847b..f21427ff69 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -44,6 +44,7 @@
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmlextensionplugin_p.h>
+#include <private/qv4executablecompilationunit_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmutex.h>
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 59651246e4..dda6e96966 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <private/qjsvalue_p.h>
#include <qtqml_tracepoints_p.h>
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 1cbad87920..8eaf8fa1f0 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -57,6 +57,7 @@
#include <private/qfinitestack_p.h>
#include <private/qrecursionwatcher_p.h>
#include <private/qqmlprofiler_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <qpointer.h>
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 247145ac0c..9c7a69d571 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -54,6 +54,7 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmltypedata_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
new file mode 100644
index 0000000000..69b26894a8
--- /dev/null
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qv4runtimecodegen_p.h>
+#include <private/qv4script_p.h>
+
+#include <QtCore/qloggingcategory.h>
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
+
+QT_BEGIN_NAMESPACE
+
+QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
+ : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
+ , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
+{
+}
+
+QQmlScriptBlob::~QQmlScriptBlob()
+{
+}
+
+QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
+{
+ if (!diskCacheDisabled() || diskCacheForced()) {
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
+ = QV4::ExecutableCompilationUnit::create();
+ QString error;
+ if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ initializeFromCompilationUnit(unit);
+ return;
+ } else {
+ qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
+ }
+ }
+
+ if (!data.exists()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ return;
+ }
+
+ QString error;
+ QString source = data.readAll(&error);
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+
+ QV4::CompiledData::CompilationUnit unit;
+
+ if (m_isModule) {
+ QList<QQmlJS::DiagnosticMessage> diagnostics;
+ unit = QV4::Compiler::Codegen::compileModule(isDebugging(), urlString(), source,
+ data.sourceTimeStamp(), &diagnostics);
+ QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ } else {
+ QmlIR::Document irUnit(isDebugging());
+
+ irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
+
+ QmlIR::ScriptDirectivesCollector collector(&irUnit);
+ irUnit.jsParserEngine.setDirectives(&collector);
+
+ QList<QQmlError> errors;
+ irUnit.javaScriptCompilationUnit = QV4::Script::precompile(
+ &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
+ source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML);
+
+ source.clear();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+
+ QmlIR::QmlUnitGenerator qmlGenerator;
+ qmlGenerator.generate(irUnit);
+ unit = std::move(irUnit.javaScriptCompilationUnit);
+ }
+
+ auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
+
+ if ((!diskCacheDisabled() || diskCacheForced()) && !isDebugging()) {
+ QString errorString;
+ if (executableUnit->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!executableUnit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ // ignore error, keep using the in-memory compilation unit.
+ }
+ } else {
+ qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of"
+ << executableUnit->fileName() << "to disk:" << errorString;
+ }
+ }
+
+ initializeFromCompilationUnit(executableUnit);
+}
+
+void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+{
+ initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
+ QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
+}
+
+void QQmlScriptBlob::done()
+{
+ if (isError())
+ return;
+
+ // Check all script dependencies for errors
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QQmlError> errors = script.script->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ if (!m_isModule) {
+ m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
+
+ QSet<QString> ns;
+
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const ScriptReference &script = m_scripts.at(scriptIndex);
+
+ m_scriptData->scripts.append(script.script);
+
+ if (!script.nameSpace.isNull()) {
+ if (!ns.contains(script.nameSpace)) {
+ ns.insert(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
+ }
+ }
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
+ }
+
+ m_importCache.populateCache(m_scriptData->typeNameCache);
+ }
+ m_scripts.clear();
+}
+
+QString QQmlScriptBlob::stringAt(int index) const
+{
+ return m_scriptData->m_precompiledScript->stringAt(index);
+}
+
+void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
+{
+ ScriptReference ref;
+ ref.script = blob;
+ ref.location = location;
+ ref.qualifier = qualifier;
+ ref.nameSpace = nameSpace;
+
+ m_scripts << ref;
+}
+
+void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
+{
+ Q_ASSERT(!m_scriptData);
+ m_scriptData.adopt(new QQmlScriptData());
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->m_precompiledScript = unit;
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> script = m_scriptData->m_precompiledScript;
+
+ if (!m_isModule) {
+ QList<QQmlError> errors;
+ for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = script->importAt(i);
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return;
+ }
+ }
+ }
+
+ auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
+
+ v4->injectModule(unit);
+
+ for (const QString &request: unit->moduleRequests()) {
+ if (v4->moduleForUrl(QUrl(request), unit.data()))
+ continue;
+
+ const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
+ addDependency(blob.data());
+ scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob_p.h b/src/qml/qml/qqmlscriptblob_p.h
new file mode 100644
index 0000000000..10c0437e7b
--- /dev/null
+++ b/src/qml/qml/qqmlscriptblob_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSCRIPTBLOB_P_H
+#define QQMLSCRIPTBLOB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlScriptData;
+class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
+
+public:
+ ~QQmlScriptBlob() override;
+
+ struct ScriptReference
+ {
+ QV4::CompiledData::Location location;
+ QString qualifier;
+ QString nameSpace;
+ QQmlRefPointer<QQmlScriptBlob> script;
+ };
+
+ QQmlRefPointer<QQmlScriptData> scriptData() const;
+
+protected:
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void done() override;
+
+ QString stringAt(int index) const override;
+
+private:
+ void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ void initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit);
+
+ QList<ScriptReference> m_scripts;
+ QQmlRefPointer<QQmlScriptData> m_scriptData;
+ const bool m_isModule;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSCRIPTBLOB_P_H
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
new file mode 100644
index 0000000000..0725f40d2a
--- /dev/null
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4module_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlScriptData::QQmlScriptData()
+ : typeNameCache(nullptr)
+ , m_loaded(false)
+{
+}
+
+QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
+{
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+
+ if (m_precompiledScript->isESModule())
+ return nullptr;
+
+ auto qmlContextData = new QQmlContextData();
+
+ qmlContextData->isInternal = true;
+ qmlContextData->isJSContext = true;
+ if (m_precompiledScript->isSharedLibrary())
+ qmlContextData->isPragmaLibraryContext = true;
+ else
+ qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
+ qmlContextData->baseUrl = url;
+ qmlContextData->baseUrlString = urlString;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!typeNameCache->isEmpty()) {
+ qmlContextData->imports = typeNameCache;
+ } else if (!m_precompiledScript->isSharedLibrary()) {
+ qmlContextData->imports = parentQmlContextData->imports;
+ qmlContextData->importedScripts = parentQmlContextData->importedScripts;
+ }
+
+ if (!m_precompiledScript->isSharedLibrary()) {
+ qmlContextData->setParent(parentQmlContextData);
+ } else {
+ qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
+ }
+
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::Scope scope(v4);
+ QV4::ScopedObject scriptsArray(scope);
+ if (qmlContextData->importedScripts.isNullOrUndefined()) {
+ scriptsArray = v4->newArrayObject(scripts.count());
+ qmlContextData->importedScripts.set(v4, scriptsArray);
+ } else {
+ scriptsArray = qmlContextData->importedScripts.valueRef();
+ }
+ QV4::ScopedValue v(scope);
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scriptsArray->put(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData)));
+
+ return qmlContextData;
+}
+
+QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
+{
+ if (m_loaded)
+ return m_value.value();
+
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::Scope scope(v4);
+
+ if (!hasEngine()) {
+ addToEngine(parentQmlContextData->engine);
+ addref();
+ }
+
+ QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData);
+ QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
+ if (qmlContextData)
+ qmlExecutionContext =
+ QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr);
+
+ QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
+ if (module) {
+ if (qmlContextData) {
+ module->d()->scope->outer.set(v4, qmlExecutionContext->d());
+ qmlExecutionContext->d()->qml()->module.set(v4, module->d());
+ }
+
+ module->evaluate();
+ }
+
+ if (v4->hasException) {
+ QQmlError error = v4->catchExceptionAsQmlError();
+ if (error.isValid())
+ QQmlEnginePrivate::get(v4)->warning(error);
+ }
+
+ QV4::ScopedValue value(scope);
+ if (qmlContextData)
+ value = qmlExecutionContext->d()->qml();
+ else if (module)
+ value = module->d();
+
+ if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) {
+ m_loaded = true;
+ m_value.set(v4, value);
+ }
+
+ return value->asReturnedValue();
+}
+
+void QQmlScriptData::clear()
+{
+ if (typeNameCache) {
+ typeNameCache->release();
+ typeNameCache = nullptr;
+ }
+
+ scripts.clear();
+
+ // An addref() was made when the QQmlCleanup was added to the engine.
+ release();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptdata_p.h b/src/qml/qml/qqmlscriptdata_p.h
new file mode 100644
index 0000000000..273ba3691f
--- /dev/null
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSCRIPTDATA_P_H
+#define QQMLSCRIPTDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmlcleanup_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4persistent_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeNameCache;
+class QQmlContextData;
+
+// QQmlScriptData instances are created, uninitialized, by the loader in the
+// load thread. The first time they are used by the VME, they are initialized which
+// creates their v8 objects and they are referenced and added to the engine's cleanup
+// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
+// reference that was created is released but final deletion only occurs once all the
+// references as released. This is all intended to ensure that the v8 resources are
+// only created and destroyed in the main thread :)
+class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlScriptData();
+
+public:
+ QUrl url;
+ QString urlString;
+ QQmlTypeNameCache *typeNameCache;
+ QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
+
+ QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
+
+protected:
+ void clear() override; // From QQmlCleanup
+
+private:
+ friend class QQmlScriptBlob;
+
+ void initialize(QQmlEngine *);
+ QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
+
+ bool m_loaded;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
+ QV4::PersistentValue m_value;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSCRIPTDATA_P_H
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
new file mode 100644
index 0000000000..b04a887ee4
--- /dev/null
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -0,0 +1,842 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertyvalidator_p.h>
+#include <private/qqmlirloader_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmlscriptdata_p.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcryptographichash.h>
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeData::TypeDataCallback::~TypeDataCallback()
+{
+}
+
+QString QQmlTypeData::TypeReference::qualifiedName() const
+{
+ QString result;
+ if (!prefix.isEmpty()) {
+ result = prefix + QLatin1Char('.');
+ }
+ result.append(type.qmlTypeName());
+ return result;
+}
+
+QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
+ : QQmlTypeLoader::Blob(url, QmlFile, manager),
+ m_typesResolved(false), m_implicitImportLoaded(false)
+{
+
+}
+
+QQmlTypeData::~QQmlTypeData()
+{
+ m_scripts.clear();
+ m_compositeSingletons.clear();
+ m_resolvedTypes.clear();
+}
+
+const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
+{
+ return m_scripts;
+}
+
+QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
+{
+ return m_compiledData.data();
+}
+
+void QQmlTypeData::registerCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(!m_callbacks.contains(callback));
+ m_callbacks.append(callback);
+}
+
+void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(m_callbacks.contains(callback));
+ m_callbacks.removeOne(callback);
+ Q_ASSERT(!m_callbacks.contains(callback));
+}
+
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (diskCacheDisabled() && !diskCacheForced())
+ return false;
+
+ if (isDebugging())
+ return false;
+
+ QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
+ if (!v4)
+ return false;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
+ {
+ QString error;
+ if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
+ return false;
+ }
+ }
+
+ if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
+ restoreIR(std::move(*unit));
+ return true;
+ }
+
+ m_compiledData = unit;
+
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
+ m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ // For remote URLs, we don't delay the loading of the implicit import
+ // because the loading probably requires an asynchronous fetch of the
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return false;
+
+ // find the implicit import
+ for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
+ if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
+ && import->qualifierIndex == 0
+ && import->majorVersion == -1
+ && import->minorVersion == -1) {
+ QList<QQmlError> errors;
+ if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
+ setError(errors);
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
+ QList<QQmlError> errors;
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void QQmlTypeData::createTypeAndPropertyCaches(
+ const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
+{
+ Q_ASSERT(m_compiledData);
+ m_compiledData->typeNameCache = typeNameCache;
+ m_compiledData->resolvedTypes = resolvedTypeCache;
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
+
+ {
+ QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
+ &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
+ m_compiledData.data(), &m_importCache);
+ QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
+ if (error.isValid()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
+ &m_compiledData->propertyCaches, m_compiledData.data());
+ aliasCreator.appendAliasPropertiesToMetaObjects();
+
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
+}
+
+static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
+{
+ for (const auto &typeRef: typeRefs) {
+ if (typeRef.typeData) {
+ const auto unit = typeRef.typeData->compilationUnit()->unitData();
+ hash->addData(unit->md5Checksum, sizeof(unit->md5Checksum));
+ } else if (typeRef.type.isValid()) {
+ const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject());
+ bool ok = false;
+ hash->addData(propertyCache->checksum(&ok));
+ if (!ok)
+ return false;
+ }
+ }
+ return true;
+}
+
+void QQmlTypeData::done()
+{
+ auto cleanup = qScopeGuard([this]{
+ m_document.reset();
+ m_typeReferences.clear();
+ if (isError())
+ m_compiledData = nullptr;
+ });
+
+ if (isError())
+ return;
+
+ // Check all script dependencies for errors
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QQmlError> errors = script.script->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ // Check all type dependencies for errors
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ ++it) {
+ const TypeReference &type = *it;
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ const QString typeName = stringAt(it.key());
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ // Check all composite singleton type dependencies for errors
+ for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
+ const TypeReference &type = m_compositeSingletons.at(ii);
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ QString typeName = type.type.qmlTypeName();
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+ QV4::ResolvedTypeReferenceMap resolvedTypeCache;
+ {
+ QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
+ if (error.isValid()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlEngine *const engine = typeLoader()->engine();
+
+ const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ return (resolvedTypeCache.addToHash(&hash, engine)
+ && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
+ ? hash.result()
+ : QByteArray();
+ };
+
+ // verify if any dependencies changed if we're using a cache
+ if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
+ qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
+ if (!loadFromSource())
+ return;
+ m_backupSourceCode = SourceCodeData();
+ m_compiledData = nullptr;
+ }
+
+ if (!m_document.isNull()) {
+ // Compile component
+ compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
+ } else {
+ createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ }
+
+ if (isError())
+ return;
+
+ {
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ {
+ // Sanity check property bindings
+ QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
+ QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ }
+
+ m_compiledData->finalizeCompositeType(enginePrivate);
+ }
+
+ {
+ QQmlType type = QQmlMetaType::qmlType(finalUrl(), true);
+ if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
+ if (!type.isValid()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
+ setError(error);
+ return;
+ } else if (!type.isCompositeSingleton()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
+ setError(error);
+ return;
+ }
+ } else {
+ // If the type is CompositeSingleton but there was no pragma Singleton in the
+ // QML file, lets report an error.
+ if (type.isValid() && type.isCompositeSingleton()) {
+ QString typeName = type.qmlTypeName();
+ setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
+ return;
+ }
+ }
+ }
+
+ {
+ // Collect imported scripts
+ m_compiledData->dependentScripts.reserve(m_scripts.count());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
+
+ QStringRef qualifier(&script.qualifier);
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex).toString();
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
+
+ m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
+ m_compiledData->dependentScripts << scriptData;
+ }
+ }
+}
+
+void QQmlTypeData::completed()
+{
+ // Notify callbacks
+ while (!m_callbacks.isEmpty()) {
+ TypeDataCallback *callback = m_callbacks.takeFirst();
+ callback->typeDataReady(this);
+ }
+}
+
+bool QQmlTypeData::loadImplicitImport()
+{
+ m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
+ // For local urls, add an implicit import "." as most overridden lookup.
+ // This will also trigger the loading of the qmldir and the import of any native
+ // types from available plugins.
+ QList<QQmlError> implicitImportErrors;
+ m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
+
+ if (!implicitImportErrors.isEmpty()) {
+ setError(implicitImportErrors);
+ return false;
+ }
+
+ return true;
+}
+
+void QQmlTypeData::dataReceived(const SourceCodeData &data)
+{
+ m_backupSourceCode = data;
+
+ if (tryLoadFromDiskCache())
+ return;
+
+ if (isError())
+ return;
+
+ if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else if (!m_backupSourceCode.exists())
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ else
+ setError(QQmlTypeLoader::tr("File is empty"));
+ return;
+ }
+
+ if (!loadFromSource())
+ return;
+
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QQmlIRLoader loader(unit, m_document.data());
+ loader.load();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
+ m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
+ continueLoadFromIR();
+}
+
+bool QQmlTypeData::loadFromSource()
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
+ QQmlEngine *qmlEngine = typeLoader()->engine();
+ QmlIR::IRBuilder compiler(qmlEngine->handle()->illegalNames());
+
+ QString sourceError;
+ const QString source = m_backupSourceCode.readAll(&sourceError);
+ if (!sourceError.isEmpty()) {
+ setError(sourceError);
+ return false;
+ }
+
+ if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
+ QList<QQmlError> errors;
+ errors.reserve(compiler.errors.count());
+ for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
+ QQmlError e;
+ e.setUrl(url());
+ e.setLine(msg.line);
+ e.setColumn(msg.column);
+ e.setDescription(msg.message);
+ errors << e;
+ }
+ setError(errors);
+ return false;
+ }
+ return true;
+}
+
+void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QQmlIRLoader loader(unit.unitData(), m_document.data());
+ loader.load();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
+ m_document->javaScriptCompilationUnit = std::move(unit);
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::continueLoadFromIR()
+{
+ m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ // For remote URLs, we don't delay the loading of the implicit import
+ // because the loading probably requires an asynchronous fetch of the
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return;
+ // This qmldir is for the implicit import
+ QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
+ auto implicitImport = pool->New<QV4::CompiledData::Import>();
+ implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
+ implicitImport->qualifierIndex = 0; // empty string
+ implicitImport->majorVersion = -1;
+ implicitImport->minorVersion = -1;
+ QList<QQmlError> errors;
+
+ if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
+ setError(errors);
+ return;
+ }
+ }
+ }
+
+ QList<QQmlError> errors;
+
+ for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return;
+ }
+ }
+}
+
+void QQmlTypeData::allDependenciesDone()
+{
+ QQmlTypeLoader::Blob::allDependenciesDone();
+
+ if (!m_typesResolved) {
+ // Check that all imports were resolved
+ QList<QQmlError> errors;
+ QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
+ for ( ; it != end; ++it) {
+ if (*it == 0) {
+ // This import was not resolved
+ for (auto keyIt = m_unresolvedImports.keyBegin(),
+ keyEnd = m_unresolvedImports.keyEnd();
+ keyIt != keyEnd; ++keyIt) {
+ const QV4::CompiledData::Import *import = *keyIt;
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex)));
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error);
+ }
+ }
+ }
+ if (errors.size()) {
+ setError(errors);
+ return;
+ }
+
+ resolveTypes();
+ m_typesResolved = true;
+ }
+}
+
+void QQmlTypeData::downloadProgressChanged(qreal p)
+{
+ for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ TypeDataCallback *callback = m_callbacks.at(ii);
+ callback->typeDataProgress(this, p);
+ }
+}
+
+QString QQmlTypeData::stringAt(int index) const
+{
+ if (m_compiledData)
+ return m_compiledData->stringAt(index);
+ return m_document->jsGenerator.stringTable.stringForIndex(index);
+}
+
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
+{
+ Q_ASSERT(m_compiledData.isNull());
+
+ const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit.unitData()
+ && (m_document->javaScriptCompilationUnit.unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+
+ QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
+ m_compiledData = compiler.compile();
+ if (!m_compiledData) {
+ setError(compiler.compilationErrors());
+ return;
+ }
+
+ const bool trySaveToDisk = (!diskCacheDisabled() || diskCacheForced())
+ && !m_document->jsModule.debugMode && !typeRecompilation;
+ if (trySaveToDisk) {
+ QString errorString;
+ if (m_compiledData->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ // ignore error, keep using the in-memory compilation unit.
+ }
+ } else {
+ qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
+ }
+ }
+}
+
+void QQmlTypeData::resolveTypes()
+{
+ // Add any imported scripts to our resolved set
+ const auto resolvedScripts = m_importCache.resolvedScripts();
+ for (const QQmlImports::ScriptReference &script : resolvedScripts) {
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
+ addDependency(blob.data());
+
+ ScriptReference ref;
+ //ref.location = ...
+ if (!script.qualifier.isEmpty())
+ {
+ ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(script.qualifier);
+ } else {
+ ref.qualifier = script.nameSpace;
+ }
+
+ ref.script = blob;
+ m_scripts << ref;
+ }
+
+ // Lets handle resolved composite singleton types
+ const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
+ for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
+ TypeReference ref;
+ QString typeName;
+ if (!csRef.prefix.isEmpty()) {
+ typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(csRef.prefix);
+ } else {
+ typeName = csRef.typeName;
+ }
+
+ int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
+ int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1;
+
+ if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true,
+ QQmlType::CompositeSingletonType))
+ return;
+
+ if (ref.type.isCompositeSingleton()) {
+ ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
+ if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) {
+ // TODO: give an error message? If so, we should record and show the path of the cycle.
+ continue;
+ }
+ addDependency(ref.typeData.data());
+ ref.prefix = csRef.prefix;
+
+ m_compositeSingletons << ref;
+ }
+ }
+
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
+ unresolvedRef != end; ++unresolvedRef) {
+
+ TypeReference ref; // resolved reference
+
+ const bool reportErrors = unresolvedRef->errorWhenNotFound;
+
+ int majorVersion = -1;
+ int minorVersion = -1;
+
+ const QString name = stringAt(unresolvedRef.key());
+
+ if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
+ unresolvedRef->location.column, reportErrors,
+ QQmlType::AnyRegistrationType) && reportErrors)
+ return;
+
+ if (ref.type.isComposite()) {
+ ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
+ addDependency(ref.typeData.data());
+ }
+ ref.majorVersion = majorVersion;
+ ref.minorVersion = minorVersion;
+
+ ref.location.line = unresolvedRef->location.line;
+ ref.location.column = unresolvedRef->location.column;
+
+ ref.needsCreation = unresolvedRef->needsCreation;
+
+ m_resolvedTypes.insert(unresolvedRef.key(), ref);
+ }
+
+ // ### this allows enums to work without explicit import or instantiation of the type
+ if (!m_implicitImportLoaded)
+ loadImplicitImport();
+}
+
+QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const
+{
+ typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
+
+ for (const QString &ns: m_namespaces)
+ (*typeNameCache)->add(ns);
+
+ // Add any Composite Singletons that were used to the import cache
+ for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
+ (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
+
+ m_importCache.populateCache(typeNameCache->data());
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
+ QScopedPointer<QV4::ResolvedTypeReference> ref(new QV4::ResolvedTypeReference);
+ QQmlType qmlType = resolvedType->type;
+ if (resolvedType->typeData) {
+ if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
+ return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
+ }
+ ref->compilationUnit = resolvedType->typeData->compilationUnit();
+ } else if (qmlType.isValid()) {
+ ref->type = qmlType;
+ Q_ASSERT(ref->type.isValid());
+
+ if (resolvedType->needsCreation && !ref->type.isCreatable()) {
+ QString reason = ref->type.noCreationReason();
+ if (reason.isEmpty())
+ reason = tr("Element is not creatable.");
+ return qQmlCompileError(resolvedType->location, reason);
+ }
+
+ if (ref->type.containsRevisionedAttributes()) {
+ ref->typePropertyCache = engine->cache(ref->type,
+ resolvedType->minorVersion);
+ }
+ }
+ ref->majorVersion = resolvedType->majorVersion;
+ ref->minorVersion = resolvedType->minorVersion;
+ ref->doDynamicTypeCheck();
+ resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ }
+ QQmlJS::DiagnosticMessage noError;
+ return noError;
+}
+
+bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ TypeReference &ref, int lineNumber, int columnNumber,
+ bool reportErrors, QQmlType::RegistrationType registrationType)
+{
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+
+ bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
+ &typeNamespace, &errors, registrationType);
+ if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
+ // Lazy loading of implicit import
+ if (loadImplicitImport()) {
+ // Try again to find the type
+ errors.clear();
+ typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
+ &typeNamespace, &errors, registrationType);
+ } else {
+ return false; //loadImplicitImport() hit an error, and called setError already
+ }
+ }
+
+ if ((!typeFound || typeNamespace) && reportErrors) {
+ // Known to not be a type:
+ // - known to be a namespace (Namespace {})
+ // - type with unknown namespace (UnknownNamespace.SomeType {})
+ QQmlError error;
+ if (typeNamespace) {
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_importCache.baseUrl());
+ error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
+ }
+
+ if (lineNumber != -1)
+ error.setLine(lineNumber);
+ if (columnNumber != -1)
+ error.setColumn(columnNumber);
+
+ errors.prepend(error);
+ setError(errors);
+ return false;
+ }
+
+ return true;
+}
+
+void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+{
+ ScriptReference ref;
+ ref.script = blob;
+ ref.location = location;
+ ref.qualifier = qualifier;
+
+ m_scripts << ref;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
new file mode 100644
index 0000000000..e1d0c900ea
--- /dev/null
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPEDATA_P_H
+#define QQMLTYPEDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypeloader_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
+public:
+ struct TypeReference
+ {
+ TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
+
+ QV4::CompiledData::Location location;
+ QQmlType type;
+ int majorVersion;
+ int minorVersion;
+ QQmlRefPointer<QQmlTypeData> typeData;
+ QString prefix; // used by CompositeSingleton types
+ QString qualifiedName() const;
+ bool needsCreation;
+ };
+
+ struct ScriptReference
+ {
+ QV4::CompiledData::Location location;
+ QString qualifier;
+ QQmlRefPointer<QQmlScriptBlob> script;
+ };
+
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlTypeData(const QUrl &, QQmlTypeLoader *);
+
+public:
+ ~QQmlTypeData() override;
+
+ const QList<ScriptReference> &resolvedScripts() const;
+
+ QV4::ExecutableCompilationUnit *compilationUnit() const;
+
+ // Used by QQmlComponent to get notifications
+ struct TypeDataCallback {
+ virtual ~TypeDataCallback();
+ virtual void typeDataProgress(QQmlTypeData *, qreal) {}
+ virtual void typeDataReady(QQmlTypeData *) {}
+ };
+ void registerCallback(TypeDataCallback *);
+ void unregisterCallback(TypeDataCallback *);
+
+protected:
+ void done() override;
+ void completed() override;
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void allDependenciesDone() override;
+ void downloadProgressChanged(qreal) override;
+
+ QString stringAt(int index) const override;
+
+private:
+ bool tryLoadFromDiskCache();
+ bool loadFromSource();
+ void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
+ void continueLoadFromIR();
+ void resolveTypes();
+ QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const;
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
+ void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::ResolvedTypeReferenceMap &resolvedTypeCache);
+ bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
+ bool reportErrors = true,
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
+
+ void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+
+
+ SourceCodeData m_backupSourceCode; // used when cache verification fails.
+ QScopedPointer<QmlIR::Document> m_document;
+ QV4::CompiledData::TypeReferenceMap m_typeReferences;
+
+ QList<ScriptReference> m_scripts;
+
+ QSet<QString> m_namespaces;
+ QList<TypeReference> m_compositeSingletons;
+
+ // map from name index to resolved type
+ // While this could be a hash, a map is chosen here to provide a stable
+ // order, which is used to calculating a check-sum on dependent meta-objects.
+ QMap<int, TypeReference> m_resolvedTypes;
+ bool m_typesResolved:1;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
+
+ QList<TypeDataCallback *> m_callbacks;
+
+ bool m_implicitImportLoaded;
+ bool loadImplicitImport();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPEDATA_P_H
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 0bfdbdd2fa..46207e6b57 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -37,77 +37,37 @@
**
****************************************************************************/
-#include "qqmltypeloader_p.h"
-#include "qqmlabstracturlinterceptor.h"
-#include "qqmlexpression_p.h"
-
-#include <private/qqmlengine_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlthread_p.h>
-#include <private/qv4codegen_p.h>
-#include <private/qqmlcomponent_p.h>
+#include <private/qqmltypeloader_p.h>
+
+#include <private/qqmldirdata_p.h>
#include <private/qqmlprofiler_p.h>
-#include <private/qqmltypecompiler_p.h>
-#include <private/qqmlpropertyvalidator_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-#include <private/qv4module_p.h>
-#include <private/qqmlirloader_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#include <QtQml/qqmlabstracturlinterceptor.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlextensioninterface.h>
+#include <QtQml/qqmlfile.h>
#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
-#include <QtQml/qqmlfile.h>
-#include <QtCore/qdiriterator.h>
-#include <QtQml/qqmlcomponent.h>
-#include <QtCore/qwaitcondition.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtQml/qqmlextensioninterface.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qscopeguard.h>
#include <functional>
-#if defined (Q_OS_UNIX)
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#if defined (QT_LINUXBASE)
-// LSB doesn't declare NAME_MAX. Use SYMLINK_MAX instead, which seems to
-// always be identical to NAME_MAX
-#ifndef NAME_MAX
-# define NAME_MAX _POSIX_SYMLINK_MAX
-#endif
-
-#endif
-
// #define DATABLOB_DEBUG
-
#ifdef DATABLOB_DEBUG
-
-#define ASSERT_MAINTHREAD() do { if (m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in main thread"); } while (false)
#define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false)
-#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
-
#else
-
-#define ASSERT_MAINTHREAD()
#define ASSERT_LOADTHREAD()
-#define ASSERT_CALLBACK()
-
#endif
-DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
-Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
-Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
-
QT_BEGIN_NAMESPACE
namespace {
@@ -121,829 +81,6 @@ namespace {
};
}
-#if QT_CONFIG(qml_network)
-// This is a lame object that we need to ensure that slots connected to
-// QNetworkReply get called in the correct thread (the loader thread).
-// As QQmlTypeLoader lives in the main thread, and we can't use
-// Qt::DirectConnection connections from a QNetworkReply (because then
-// sender() wont work), we need to insert this object in the middle.
-class QQmlTypeLoaderNetworkReplyProxy : public QObject
-{
- Q_OBJECT
-public:
- QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
-
-public slots:
- void finished();
- void downloadProgress(qint64, qint64);
- void manualFinished(QNetworkReply*);
-
-private:
- QQmlTypeLoader *l;
-};
-#endif // qml_network
-
-class QQmlTypeLoaderThread : public QQmlThread
-{
- typedef QQmlTypeLoaderThread This;
-
-public:
- QQmlTypeLoaderThread(QQmlTypeLoader *loader);
-#if QT_CONFIG(qml_network)
- QNetworkAccessManager *networkAccessManager() const;
- QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
-#endif // qml_network
- void load(QQmlDataBlob *b);
- void loadAsync(QQmlDataBlob *b);
- void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
- void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void callCompleted(QQmlDataBlob *b);
- void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
- void initializeEngine(QQmlExtensionInterface *, const char *);
-
-protected:
- void shutdownThread() override;
-
-private:
- void loadThread(QQmlDataBlob *b);
- void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void callCompletedMain(QQmlDataBlob *b);
- void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
- void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
-
- QQmlTypeLoader *m_loader;
-#if QT_CONFIG(qml_network)
- mutable QNetworkAccessManager *m_networkAccessManager;
- mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
-#endif // qml_network
-};
-
-#if QT_CONFIG(qml_network)
-QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
-: l(l)
-{
-}
-
-void QQmlTypeLoaderNetworkReplyProxy::finished()
-{
- Q_ASSERT(sender());
- Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
- l->networkReplyFinished(reply);
-}
-
-void QQmlTypeLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
-{
- Q_ASSERT(sender());
- Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
- l->networkReplyProgress(reply, bytesReceived, bytesTotal);
-}
-
-// This function is for when you want to shortcut the signals and call directly
-void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
-{
- qint64 replySize = reply->size();
- l->networkReplyProgress(reply, replySize, replySize);
- l->networkReplyFinished(reply);
-}
-#endif // qml_network
-
-/*!
-\class QQmlDataBlob
-\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
-\internal
-
-QQmlDataBlob's are loaded by a QQmlTypeLoader. The user creates the QQmlDataBlob
-and then calls QQmlTypeLoader::load() or QQmlTypeLoader::loadWithStaticData() to load it.
-The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes available.
-*/
-
-/*!
-\enum QQmlDataBlob::Status
-
-This enum describes the status of the data blob.
-
-\list
-\li Null The blob has not yet been loaded by a QQmlTypeLoader
-\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
-invoked or has not yet returned.
-\li WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
-only occurs after the QQmlDataBlob::setData() callback has been made, and when the blob has outstanding
-dependencies.
-\li Complete The blob's data has been loaded and all dependencies are done.
-\li Error An error has been set on this blob.
-\endlist
-*/
-
-/*!
-\enum QQmlDataBlob::Type
-
-This enum describes the type of the data blob.
-
-\list
-\li QmlFile This is a QQmlTypeData
-\li JavaScriptFile This is a QQmlScriptData
-\li QmldirFile This is a QQmlQmldirData
-\endlist
-*/
-
-/*!
-Create a new QQmlDataBlob for \a url and of the provided \a type.
-*/
-QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
-: m_typeLoader(manager), m_type(type), m_url(url), m_finalUrl(url), m_redirectCount(0),
- m_inCallback(false), m_isDone(false)
-{
- //Set here because we need to get the engine from the manager
- if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
- m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
- (QQmlAbstractUrlInterceptor::DataType)m_type);
-}
-
-/*! \internal */
-QQmlDataBlob::~QQmlDataBlob()
-{
- Q_ASSERT(m_waitingOnMe.isEmpty());
-
- cancelAllWaitingFor();
-}
-
-/*!
- Must be called before loading can occur.
-*/
-void QQmlDataBlob::startLoading()
-{
- Q_ASSERT(status() == QQmlDataBlob::Null);
- m_data.setStatus(QQmlDataBlob::Loading);
-}
-
-/*!
-Returns the type provided to the constructor.
-*/
-QQmlDataBlob::Type QQmlDataBlob::type() const
-{
- return m_type;
-}
-
-/*!
-Returns the blob's status.
-*/
-QQmlDataBlob::Status QQmlDataBlob::status() const
-{
- return m_data.status();
-}
-
-/*!
-Returns true if the status is Null.
-*/
-bool QQmlDataBlob::isNull() const
-{
- return status() == Null;
-}
-
-/*!
-Returns true if the status is Loading.
-*/
-bool QQmlDataBlob::isLoading() const
-{
- return status() == Loading;
-}
-
-/*!
-Returns true if the status is WaitingForDependencies.
-*/
-bool QQmlDataBlob::isWaiting() const
-{
- return status() == WaitingForDependencies ||
- status() == ResolvingDependencies;
-}
-
-/*!
-Returns true if the status is Complete.
-*/
-bool QQmlDataBlob::isComplete() const
-{
- return status() == Complete;
-}
-
-/*!
-Returns true if the status is Error.
-*/
-bool QQmlDataBlob::isError() const
-{
- return status() == Error;
-}
-
-/*!
-Returns true if the status is Complete or Error.
-*/
-bool QQmlDataBlob::isCompleteOrError() const
-{
- Status s = status();
- return s == Error || s == Complete;
-}
-
-/*!
-Returns the data download progress from 0 to 1.
-*/
-qreal QQmlDataBlob::progress() const
-{
- quint8 p = m_data.progress();
- if (p == 0xFF) return 1.;
- else return qreal(p) / qreal(0xFF);
-}
-
-/*!
-Returns the physical url of the data. Initially this is the same as
-finalUrl(), but if a URL interceptor is set, it will work on this URL
-and leave finalUrl() alone.
-
-\sa finalUrl()
-*/
-QUrl QQmlDataBlob::url() const
-{
- return m_url;
-}
-
-QString QQmlDataBlob::urlString() const
-{
- if (m_urlString.isEmpty())
- m_urlString = m_url.toString();
-
- return m_urlString;
-}
-
-/*!
-Returns the logical URL to be used for resolving further URLs referred to in
-the code.
-
-This is the blob url passed to the constructor. If a URL interceptor rewrites
-the URL, this one stays the same. If a network redirect happens while fetching
-the data, this url is updated to reflect the new location. Therefore, if both
-an interception and a redirection happen, the final url will indirectly
-incorporate the result of the interception, potentially breaking further
-lookups.
-
-\sa url()
-*/
-QUrl QQmlDataBlob::finalUrl() const
-{
- return m_finalUrl;
-}
-
-/*!
-Returns the finalUrl() as a string.
-*/
-QString QQmlDataBlob::finalUrlString() const
-{
- if (m_finalUrlString.isEmpty())
- m_finalUrlString = m_finalUrl.toString();
-
- return m_finalUrlString;
-}
-
-/*!
-Return the errors on this blob.
-
-May only be called from the load thread, or after the blob isCompleteOrError().
-*/
-QList<QQmlError> QQmlDataBlob::errors() const
-{
- Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
- return m_errors;
-}
-
-/*!
-Mark this blob as having \a errors.
-
-All outstanding dependencies will be cancelled. Requests to add new dependencies
-will be ignored. Entry into the Error state is irreversable.
-
-The setError() method may only be called from within a QQmlDataBlob callback.
-*/
-void QQmlDataBlob::setError(const QQmlError &errors)
-{
- ASSERT_CALLBACK();
-
- QList<QQmlError> l;
- l << errors;
- setError(l);
-}
-
-/*!
-\overload
-*/
-void QQmlDataBlob::setError(const QList<QQmlError> &errors)
-{
- ASSERT_CALLBACK();
-
- Q_ASSERT(status() != Error);
- Q_ASSERT(m_errors.isEmpty());
-
- m_errors = errors; // Must be set before the m_data fence
- m_data.setStatus(Error);
-
- if (dumpErrors()) {
- qWarning().nospace() << "Errors for " << urlString();
- for (int ii = 0; ii < errors.count(); ++ii)
- qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
- }
- cancelAllWaitingFor();
-
- if (!m_inCallback)
- tryDone();
-}
-
-void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
-{
- QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
- e.setDescription(error.message);
- e.setUrl(url());
- setError(e);
-}
-
-void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors)
-{
- QList<QQmlError> finalErrors;
- finalErrors.reserve(errors.count());
- for (const auto &error : errors) {
- QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
- e.setDescription(error.message);
- e.setUrl(url());
- finalErrors << e;
- }
- setError(finalErrors);
-}
-
-void QQmlDataBlob::setError(const QString &description)
-{
- QQmlError e;
- e.setDescription(description);
- e.setUrl(url());
- setError(e);
-}
-
-/*!
-Wait for \a blob to become complete or to error. If \a blob is already
-complete or in error, or this blob is already complete, this has no effect.
-
-The setError() method may only be called from within a QQmlDataBlob callback.
-*/
-void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
-{
- ASSERT_CALLBACK();
-
- Q_ASSERT(status() != Null);
-
- if (!blob ||
- blob->status() == Error || blob->status() == Complete ||
- status() == Error || status() == Complete || m_isDone)
- return;
-
- for (auto existingDep: qAsConst(m_waitingFor))
- if (existingDep.data() == blob)
- return;
-
- m_data.setStatus(WaitingForDependencies);
-
- m_waitingFor.append(blob);
- blob->m_waitingOnMe.append(this);
-}
-
-/*!
-\fn void QQmlDataBlob::dataReceived(const Data &data)
-
-Invoked when data for the blob is received. Implementors should use this callback
-to determine a blob's dependencies. Within this callback you may call setError()
-or addDependency().
-*/
-
-/*!
-Invoked once data has either been received or a network error occurred, and all
-dependencies are complete.
-
-You can set an error in this method, but you cannot add new dependencies. Implementors
-should use this callback to finalize processing of data.
-
-The default implementation does nothing.
-
-XXX Rename processData() or some such to avoid confusion between done() (processing thread)
-and completed() (main thread)
-*/
-void QQmlDataBlob::done()
-{
-}
-
-#if QT_CONFIG(qml_network)
-/*!
-Invoked if there is a network error while fetching this blob.
-
-The default implementation sets an appropriate QQmlError.
-*/
-void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
-{
- Q_UNUSED(networkError);
-
- QQmlError error;
- error.setUrl(m_url);
-
- const char *errorString = nullptr;
- switch (networkError) {
- default:
- errorString = "Network error";
- break;
- case QNetworkReply::ConnectionRefusedError:
- errorString = "Connection refused";
- break;
- case QNetworkReply::RemoteHostClosedError:
- errorString = "Remote host closed the connection";
- break;
- case QNetworkReply::HostNotFoundError:
- errorString = "Host not found";
- break;
- case QNetworkReply::TimeoutError:
- errorString = "Timeout";
- break;
- case QNetworkReply::ProxyConnectionRefusedError:
- case QNetworkReply::ProxyConnectionClosedError:
- case QNetworkReply::ProxyNotFoundError:
- case QNetworkReply::ProxyTimeoutError:
- case QNetworkReply::ProxyAuthenticationRequiredError:
- case QNetworkReply::UnknownProxyError:
- errorString = "Proxy error";
- break;
- case QNetworkReply::ContentAccessDenied:
- errorString = "Access denied";
- break;
- case QNetworkReply::ContentNotFoundError:
- errorString = "File not found";
- break;
- case QNetworkReply::AuthenticationRequiredError:
- errorString = "Authentication required";
- break;
- };
-
- error.setDescription(QLatin1String(errorString));
-
- setError(error);
-}
-#endif // qml_network
-
-/*!
-Called if \a blob, which was previously waited for, has an error.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
-{
- Q_UNUSED(blob);
-}
-
-/*!
-Called if \a blob, which was previously waited for, has completed.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
-{
- Q_UNUSED(blob);
-}
-
-/*!
-Called when all blobs waited for have completed. This occurs regardless of
-whether they are in error, or complete state.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::allDependenciesDone()
-{
- m_data.setStatus(QQmlDataBlob::ResolvingDependencies);
-}
-
-/*!
-Called when the download progress of this blob changes. \a progress goes
-from 0 to 1.
-
-This callback is only invoked if an asynchronous load for this blob is
-made. An asynchronous load is one in which the Asynchronous mode is
-specified explicitly, or one that is implicitly delayed due to a network
-operation.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::downloadProgressChanged(qreal progress)
-{
- Q_UNUSED(progress);
-}
-
-/*!
-Invoked on the main thread sometime after done() was called on the load thread.
-
-You cannot modify the blobs state at all in this callback and cannot depend on the
-order or timeliness of these callbacks. Implementors should use this callback to notify
-dependencies on the main thread that the blob is done and not a lot else.
-
-This callback is only invoked if an asynchronous load for this blob is
-made. An asynchronous load is one in which the Asynchronous mode is
-specified explicitly, or one that is implicitly delayed due to a network
-operation.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::completed()
-{
-}
-
-
-void QQmlDataBlob::tryDone()
-{
- if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
- m_isDone = true;
- addref();
-
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
-#endif
- done();
-
- if (status() != Error)
- m_data.setStatus(Complete);
-
- notifyAllWaitingOnMe();
-
- // Locking is not required here, as anyone expecting callbacks must
- // already be protected against the blob being completed (as set above);
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob: Dispatching completed");
-#endif
- m_typeLoader->m_thread->callCompleted(this);
-
- release();
- }
-}
-
-void QQmlDataBlob::cancelAllWaitingFor()
-{
- while (m_waitingFor.count()) {
- QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
-
- Q_ASSERT(blob->m_waitingOnMe.contains(this));
-
- blob->m_waitingOnMe.removeOne(this);
- }
-}
-
-void QQmlDataBlob::notifyAllWaitingOnMe()
-{
- while (m_waitingOnMe.count()) {
- QQmlDataBlob *blob = m_waitingOnMe.takeLast();
-
- Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
- [this](const QQmlRefPointer<QQmlDataBlob> &waiting) { return waiting.data() == this; }));
-
- blob->notifyComplete(this);
- }
-}
-
-void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
-{
- Q_ASSERT(blob->status() == Error || blob->status() == Complete);
- QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
-
- m_inCallback = true;
-
- QQmlRefPointer<QQmlDataBlob> blobRef;
- for (int i = 0; i < m_waitingFor.count(); ++i) {
- if (m_waitingFor.at(i).data() == blob) {
- blobRef = m_waitingFor.takeAt(i);
- break;
- }
- }
- Q_ASSERT(blobRef);
-
- if (blob->status() == Error) {
- dependencyError(blob);
- } else if (blob->status() == Complete) {
- dependencyComplete(blob);
- }
-
- if (!isError() && m_waitingFor.isEmpty())
- allDependenciesDone();
-
- m_inCallback = false;
-
- tryDone();
-}
-
-#define TD_STATUS_MASK 0x0000FFFF
-#define TD_STATUS_SHIFT 0
-#define TD_PROGRESS_MASK 0x00FF0000
-#define TD_PROGRESS_SHIFT 16
-#define TD_ASYNC_MASK 0x80000000
-
-QQmlDataBlob::ThreadData::ThreadData()
-: _p(0)
-{
-}
-
-QQmlDataBlob::Status QQmlDataBlob::ThreadData::status() const
-{
- return QQmlDataBlob::Status((_p.loadRelaxed() & TD_STATUS_MASK) >> TD_STATUS_SHIFT);
-}
-
-void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status)
-{
- while (true) {
- int d = _p.loadRelaxed();
- int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-bool QQmlDataBlob::ThreadData::isAsync() const
-{
- return _p.loadRelaxed() & TD_ASYNC_MASK;
-}
-
-void QQmlDataBlob::ThreadData::setIsAsync(bool v)
-{
- while (true) {
- int d = _p.loadRelaxed();
- int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-quint8 QQmlDataBlob::ThreadData::progress() const
-{
- return quint8((_p.loadRelaxed() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT);
-}
-
-void QQmlDataBlob::ThreadData::setProgress(quint8 v)
-{
- while (true) {
- int d = _p.loadRelaxed();
- int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
-: m_loader(loader)
-#if QT_CONFIG(qml_network)
-, m_networkAccessManager(nullptr), m_networkReplyProxy(nullptr)
-#endif // qml_network
-{
- // Do that after initializing all the members.
- startup();
-}
-
-#if QT_CONFIG(qml_network)
-QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
-{
- Q_ASSERT(isThisThread());
- if (!m_networkAccessManager) {
- m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
- m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
- }
-
- return m_networkAccessManager;
-}
-
-QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
-{
- Q_ASSERT(isThisThread());
- Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
- return m_networkReplyProxy;
-}
-#endif // qml_network
-
-void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
-{
- b->addref();
- callMethodInThread(&This::loadThread, b);
-}
-
-void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
-{
- b->addref();
- postMethodToThread(&This::loadThread, b);
-}
-
-void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
-{
- b->addref();
- callMethodInThread(&This::loadWithStaticDataThread, b, d);
-}
-
-void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
-{
- b->addref();
- postMethodToThread(&This::loadWithStaticDataThread, b, d);
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- b->addref();
- callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- b->addref();
- postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
-}
-
-void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b)
-{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callCompletedMain, b);
-#else
- postMethodToMain(&This::callCompletedMain, b);
-#endif
-}
-
-void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
-{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callDownloadProgressChangedMain, b, p);
-#else
- postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
-#endif
-}
-
-void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
- const char *uri)
-{
- callMethodInMain(&This::initializeEngineMain, iface, uri);
-}
-
-void QQmlTypeLoaderThread::shutdownThread()
-{
-#if QT_CONFIG(qml_network)
- delete m_networkAccessManager;
- m_networkAccessManager = nullptr;
- delete m_networkReplyProxy;
- m_networkReplyProxy = nullptr;
-#endif // qml_network
-}
-
-void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
-{
- m_loader->loadThread(b);
- b->release();
-}
-
-void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
-{
- m_loader->loadWithStaticDataThread(b, d);
- b->release();
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- m_loader->loadWithCachedUnitThread(b, unit);
- b->release();
-}
-
-void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
-{
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
-#endif
- b->completed();
- b->release();
-}
-
-void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
-{
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
- qPrintable(b->urlString()), p);
-#endif
- b->downloadProgressChanged(p);
- b->release();
-}
-
-void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
- const char *uri)
-{
- Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
- iface->initializeEngine(m_loader->engine(), uri);
-}
-
/*!
\class QQmlTypeLoader
\brief The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
@@ -1532,6 +669,16 @@ bool QQmlTypeLoader::Blob::isDebugging() const
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
+bool QQmlTypeLoader::Blob::diskCacheDisabled()
+{
+ return disableDiskCache();
+}
+
+bool QQmlTypeLoader::Blob::diskCacheForced()
+{
+ return forceDiskCache();
+}
+
bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
{
bool resolve = true;
@@ -1564,77 +711,6 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
return true;
}
-
-QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
-{
-}
-
-bool QQmlTypeLoaderQmldirContent::hasError() const
-{
- return m_parser.hasError();
-}
-
-QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
-{
- QList<QQmlError> errors;
- const QUrl url(uri);
- for (const auto parseError : m_parser.errors(uri)) {
- QQmlError error;
- error.setUrl(url);
- error.setLine(parseError.line);
- error.setColumn(parseError.column);
- error.setDescription(parseError.message);
- errors.append(error);
- }
- return errors;
-}
-
-QString QQmlTypeLoaderQmldirContent::typeNamespace() const
-{
- return m_parser.typeNamespace();
-}
-
-void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
-{
- m_hasContent = true;
- m_location = location;
- m_parser.parse(content);
-}
-
-void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
-{
- QQmlJS::DiagnosticMessage parseError;
- parseError.line = error.line();
- parseError.column = error.column();
- parseError.message = error.description();
- m_parser.setError(parseError);
-}
-
-QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
-{
- return m_parser.components();
-}
-
-QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
-{
- return m_parser.scripts();
-}
-
-QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
-{
- return m_parser.plugins();
-}
-
-QString QQmlTypeLoaderQmldirContent::pluginLocation() const
-{
- return m_location;
-}
-
-bool QQmlTypeLoaderQmldirContent::designerSupported() const
-{
- return m_parser.designerSupported();
-}
-
/*!
Constructs a new type loader that uses the given \a engine.
*/
@@ -1788,17 +864,6 @@ QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(const QUrl &url)
return qmldirData;
}
-// #### Qt 6: Remove this function, it exists only for binary compatibility.
-/*!
- * \internal
- */
-bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
-{
- Q_UNUSED(name)
- Q_UNUSED(fileName)
- return false;
-}
-
/*!
Returns the absolute filename of path via a directory cache.
Returns a empty string if the path does not exist.
@@ -2109,1221 +1174,4 @@ bool QQmlTypeLoader::isScriptLoaded(const QUrl &url) const
return m_scriptCache.contains(url);
}
-QQmlTypeData::TypeDataCallback::~TypeDataCallback()
-{
-}
-
-QString QQmlTypeData::TypeReference::qualifiedName() const
-{
- QString result;
- if (!prefix.isEmpty()) {
- result = prefix + QLatin1Char('.');
- }
- result.append(type.qmlTypeName());
- return result;
-}
-
-QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
-: QQmlTypeLoader::Blob(url, QmlFile, manager),
- m_typesResolved(false), m_implicitImportLoaded(false)
-{
-
-}
-
-QQmlTypeData::~QQmlTypeData()
-{
- m_scripts.clear();
- m_compositeSingletons.clear();
- m_resolvedTypes.clear();
-}
-
-const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
-{
- return m_scripts;
-}
-
-QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
-{
- return m_compiledData.data();
-}
-
-void QQmlTypeData::registerCallback(TypeDataCallback *callback)
-{
- Q_ASSERT(!m_callbacks.contains(callback));
- m_callbacks.append(callback);
-}
-
-void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
-{
- Q_ASSERT(m_callbacks.contains(callback));
- m_callbacks.removeOne(callback);
- Q_ASSERT(!m_callbacks.contains(callback));
-}
-
-bool QQmlTypeData::tryLoadFromDiskCache()
-{
- if (disableDiskCache() && !forceDiskCache())
- return false;
-
- if (isDebugging())
- return false;
-
- QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
- if (!v4)
- return false;
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
- {
- QString error;
- if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
- qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
- return false;
- }
- }
-
- if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
- restoreIR(std::move(*unit));
- return true;
- }
-
- m_compiledData = unit;
-
- for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
- m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
-
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- // For remote URLs, we don't delay the loading of the implicit import
- // because the loading probably requires an asynchronous fetch of the
- // qmldir (so we can't load it just in time).
- if (!finalUrl().scheme().isEmpty()) {
- QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- if (!loadImplicitImport())
- return false;
-
- // find the implicit import
- for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
- if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
- && import->qualifierIndex == 0
- && import->majorVersion == -1
- && import->minorVersion == -1) {
- QList<QQmlError> errors;
- if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
- setError(errors);
- return false;
- }
- break;
- }
- }
- }
- }
-
- for (int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
- QList<QQmlError> errors;
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return false;
- }
- }
-
- return true;
-}
-
-void QQmlTypeData::createTypeAndPropertyCaches(
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
-{
- Q_ASSERT(m_compiledData);
- m_compiledData->typeNameCache = typeNameCache;
- m_compiledData->resolvedTypes = resolvedTypeCache;
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
-
- QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
-
- {
- QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
- &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
- m_compiledData.data(), &m_importCache);
- QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
-
- QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
- &m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects();
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
-}
-
-static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
-{
- for (const auto &typeRef: typeRefs) {
- if (typeRef.typeData) {
- const auto unit = typeRef.typeData->compilationUnit()->unitData();
- hash->addData(unit->md5Checksum, sizeof(unit->md5Checksum));
- } else if (typeRef.type.isValid()) {
- const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject());
- bool ok = false;
- hash->addData(propertyCache->checksum(&ok));
- if (!ok)
- return false;
- }
- }
- return true;
-}
-
-void QQmlTypeData::done()
-{
- auto cleanup = qScopeGuard([this]{
- m_document.reset();
- m_typeReferences.clear();
- if (isError())
- m_compiledData = nullptr;
- });
-
- if (isError())
- return;
-
- // Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
- const ScriptReference &script = m_scripts.at(ii);
- Q_ASSERT(script.script->isCompleteOrError());
- if (script.script->isError()) {
- QList<QQmlError> errors = script.script->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(script.location.line);
- error.setColumn(script.location.column);
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- // Check all type dependencies for errors
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
- ++it) {
- const TypeReference &type = *it;
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
- if (type.typeData && type.typeData->isError()) {
- const QString typeName = stringAt(it.key());
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(type.location.line);
- error.setColumn(type.location.column);
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- // Check all composite singleton type dependencies for errors
- for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
- const TypeReference &type = m_compositeSingletons.at(ii);
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
- if (type.typeData && type.typeData->isError()) {
- QString typeName = type.type.qmlTypeName();
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(type.location.line);
- error.setColumn(type.location.column);
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QV4::ResolvedTypeReferenceMap resolvedTypeCache;
- {
- QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
-
- QQmlEngine *const engine = typeLoader()->engine();
-
- const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
- QCryptographicHash hash(QCryptographicHash::Md5);
- return (resolvedTypeCache.addToHash(&hash, engine)
- && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
- ? hash.result()
- : QByteArray();
- };
-
- // verify if any dependencies changed if we're using a cache
- if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
- qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
- if (!loadFromSource())
- return;
- m_backupSourceCode = SourceCodeData();
- m_compiledData = nullptr;
- }
-
- if (!m_document.isNull()) {
- // Compile component
- compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
- } else {
- createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
- }
-
- if (isError())
- return;
-
- {
- QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
- {
- // Sanity check property bindings
- QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
- QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- }
-
- m_compiledData->finalizeCompositeType(enginePrivate);
- }
-
- {
- QQmlType type = QQmlMetaType::qmlType(finalUrl(), true);
- if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
- if (!type.isValid()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
- setError(error);
- return;
- } else if (!type.isCompositeSingleton()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
- setError(error);
- return;
- }
- } else {
- // If the type is CompositeSingleton but there was no pragma Singleton in the
- // QML file, lets report an error.
- if (type.isValid() && type.isCompositeSingleton()) {
- QString typeName = type.qmlTypeName();
- setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
- return;
- }
- }
- }
-
- {
- // Collect imported scripts
- m_compiledData->dependentScripts.reserve(m_scripts.count());
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
-
- QStringRef qualifier(&script.qualifier);
- QString enclosingNamespace;
-
- const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
- if (lastDotIndex != -1) {
- enclosingNamespace = qualifier.left(lastDotIndex).toString();
- qualifier = qualifier.mid(lastDotIndex+1);
- }
-
- m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
- QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
- m_compiledData->dependentScripts << scriptData;
- }
- }
-}
-
-void QQmlTypeData::completed()
-{
- // Notify callbacks
- while (!m_callbacks.isEmpty()) {
- TypeDataCallback *callback = m_callbacks.takeFirst();
- callback->typeDataReady(this);
- }
-}
-
-bool QQmlTypeData::loadImplicitImport()
-{
- m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
-
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- // For local urls, add an implicit import "." as most overridden lookup.
- // This will also trigger the loading of the qmldir and the import of any native
- // types from available plugins.
- QList<QQmlError> implicitImportErrors;
- m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
-
- if (!implicitImportErrors.isEmpty()) {
- setError(implicitImportErrors);
- return false;
- }
-
- return true;
-}
-
-void QQmlTypeData::dataReceived(const SourceCodeData &data)
-{
- m_backupSourceCode = data;
-
- if (tryLoadFromDiskCache())
- return;
-
- if (isError())
- return;
-
- if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
- if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
- setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
- else if (!m_backupSourceCode.exists())
- setError(QQmlTypeLoader::tr("No such file or directory"));
- else
- setError(QQmlTypeLoader::tr("File is empty"));
- return;
- }
-
- if (!loadFromSource())
- return;
-
- continueLoadFromIR();
-}
-
-void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit, m_document.data());
- loader.load();
- m_document->jsModule.fileName = urlString();
- m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
- continueLoadFromIR();
-}
-
-bool QQmlTypeData::loadFromSource()
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
- QQmlEngine *qmlEngine = typeLoader()->engine();
- QmlIR::IRBuilder compiler(qmlEngine->handle()->illegalNames());
-
- QString sourceError;
- const QString source = m_backupSourceCode.readAll(&sourceError);
- if (!sourceError.isEmpty()) {
- setError(sourceError);
- return false;
- }
-
- if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
- QList<QQmlError> errors;
- errors.reserve(compiler.errors.count());
- for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
- QQmlError e;
- e.setUrl(url());
- e.setLine(msg.line);
- e.setColumn(msg.column);
- e.setDescription(msg.message);
- errors << e;
- }
- setError(errors);
- return false;
- }
- return true;
-}
-
-void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit.unitData(), m_document.data());
- loader.load();
- m_document->jsModule.fileName = urlString();
- m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = std::move(unit);
- continueLoadFromIR();
-}
-
-void QQmlTypeData::continueLoadFromIR()
-{
- m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- // For remote URLs, we don't delay the loading of the implicit import
- // because the loading probably requires an asynchronous fetch of the
- // qmldir (so we can't load it just in time).
- if (!finalUrl().scheme().isEmpty()) {
- QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- if (!loadImplicitImport())
- return;
- // This qmldir is for the implicit import
- QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
- auto implicitImport = pool->New<QV4::CompiledData::Import>();
- implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
- implicitImport->qualifierIndex = 0; // empty string
- implicitImport->majorVersion = -1;
- implicitImport->minorVersion = -1;
- QList<QQmlError> errors;
-
- if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
- setError(errors);
- return;
- }
- }
- }
-
- QList<QQmlError> errors;
-
- for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return;
- }
- }
-}
-
-void QQmlTypeData::allDependenciesDone()
-{
- QQmlTypeLoader::Blob::allDependenciesDone();
-
- if (!m_typesResolved) {
- // Check that all imports were resolved
- QList<QQmlError> errors;
- QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
- for ( ; it != end; ++it) {
- if (*it == 0) {
- // This import was not resolved
- for (auto keyIt = m_unresolvedImports.keyBegin(),
- keyEnd = m_unresolvedImports.keyEnd();
- keyIt != keyEnd; ++keyIt) {
- const QV4::CompiledData::Import *import = *keyIt;
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex)));
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error);
- }
- }
- }
- if (errors.size()) {
- setError(errors);
- return;
- }
-
- resolveTypes();
- m_typesResolved = true;
- }
-}
-
-void QQmlTypeData::downloadProgressChanged(qreal p)
-{
- for (int ii = 0; ii < m_callbacks.count(); ++ii) {
- TypeDataCallback *callback = m_callbacks.at(ii);
- callback->typeDataProgress(this, p);
- }
-}
-
-QString QQmlTypeData::stringAt(int index) const
-{
- if (m_compiledData)
- return m_compiledData->stringAt(index);
- return m_document->jsGenerator.stringTable.stringForIndex(index);
-}
-
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
-{
- Q_ASSERT(m_compiledData.isNull());
-
- const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit.unitData()
- && (m_document->javaScriptCompilationUnit.unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
-
- QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
- m_compiledData = compiler.compile();
- if (!m_compiledData) {
- setError(compiler.compilationErrors());
- return;
- }
-
- const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode && !typeRecompilation;
- if (trySaveToDisk) {
- QString errorString;
- if (m_compiledData->saveToDisk(url(), &errorString)) {
- QString error;
- if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
- // ignore error, keep using the in-memory compilation unit.
- }
- } else {
- qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
- }
- }
-}
-
-void QQmlTypeData::resolveTypes()
-{
- // Add any imported scripts to our resolved set
- const auto resolvedScripts = m_importCache.resolvedScripts();
- for (const QQmlImports::ScriptReference &script : resolvedScripts) {
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
- addDependency(blob.data());
-
- ScriptReference ref;
- //ref.location = ...
- if (!script.qualifier.isEmpty())
- {
- ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
- // Add a reference to the enclosing namespace
- m_namespaces.insert(script.qualifier);
- } else {
- ref.qualifier = script.nameSpace;
- }
-
- ref.script = blob;
- m_scripts << ref;
- }
-
- // Lets handle resolved composite singleton types
- const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
- for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
- TypeReference ref;
- QString typeName;
- if (!csRef.prefix.isEmpty()) {
- typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
- // Add a reference to the enclosing namespace
- m_namespaces.insert(csRef.prefix);
- } else {
- typeName = csRef.typeName;
- }
-
- int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
- int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1;
-
- if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true,
- QQmlType::CompositeSingletonType))
- return;
-
- if (ref.type.isCompositeSingleton()) {
- ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) {
- // TODO: give an error message? If so, we should record and show the path of the cycle.
- continue;
- }
- addDependency(ref.typeData.data());
- ref.prefix = csRef.prefix;
-
- m_compositeSingletons << ref;
- }
- }
-
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
- unresolvedRef != end; ++unresolvedRef) {
-
- TypeReference ref; // resolved reference
-
- const bool reportErrors = unresolvedRef->errorWhenNotFound;
-
- int majorVersion = -1;
- int minorVersion = -1;
-
- const QString name = stringAt(unresolvedRef.key());
-
- if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
- QQmlType::AnyRegistrationType) && reportErrors)
- return;
-
- if (ref.type.isComposite()) {
- ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- addDependency(ref.typeData.data());
- }
- ref.majorVersion = majorVersion;
- ref.minorVersion = minorVersion;
-
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
-
- ref.needsCreation = unresolvedRef->needsCreation;
-
- m_resolvedTypes.insert(unresolvedRef.key(), ref);
- }
-
- // ### this allows enums to work without explicit import or instantiation of the type
- if (!m_implicitImportLoaded)
- loadImplicitImport();
-}
-
-QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const
-{
- typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
-
- for (const QString &ns: m_namespaces)
- (*typeNameCache)->add(ns);
-
- // Add any Composite Singletons that were used to the import cache
- for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
- (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
-
- m_importCache.populateCache(typeNameCache->data());
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
-
- for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
- QScopedPointer<QV4::ResolvedTypeReference> ref(new QV4::ResolvedTypeReference);
- QQmlType qmlType = resolvedType->type;
- if (resolvedType->typeData) {
- if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
- return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
- }
- ref->compilationUnit = resolvedType->typeData->compilationUnit();
- } else if (qmlType.isValid()) {
- ref->type = qmlType;
- Q_ASSERT(ref->type.isValid());
-
- if (resolvedType->needsCreation && !ref->type.isCreatable()) {
- QString reason = ref->type.noCreationReason();
- if (reason.isEmpty())
- reason = tr("Element is not creatable.");
- return qQmlCompileError(resolvedType->location, reason);
- }
-
- if (ref->type.containsRevisionedAttributes()) {
- ref->typePropertyCache = engine->cache(ref->type,
- resolvedType->minorVersion);
- }
- }
- ref->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
- ref->doDynamicTypeCheck();
- resolvedTypeCache->insert(resolvedType.key(), ref.take());
- }
- QQmlJS::DiagnosticMessage noError;
- return noError;
-}
-
-bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
- TypeReference &ref, int lineNumber, int columnNumber,
- bool reportErrors, QQmlType::RegistrationType registrationType)
-{
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
-
- bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
- if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
- // Lazy loading of implicit import
- if (loadImplicitImport()) {
- // Try again to find the type
- errors.clear();
- typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
- } else {
- return false; //loadImplicitImport() hit an error, and called setError already
- }
- }
-
- if ((!typeFound || typeNamespace) && reportErrors) {
- // Known to not be a type:
- // - known to be a namespace (Namespace {})
- // - type with unknown namespace (UnknownNamespace.SomeType {})
- QQmlError error;
- if (typeNamespace) {
- error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
- } else {
- if (errors.size()) {
- error = errors.takeFirst();
- } else {
- // this should not be possible!
- // Description should come from error provided by addImport() function.
- error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
- }
- error.setUrl(m_importCache.baseUrl());
- error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
- }
-
- if (lineNumber != -1)
- error.setLine(lineNumber);
- if (columnNumber != -1)
- error.setColumn(columnNumber);
-
- errors.prepend(error);
- setError(errors);
- return false;
- }
-
- return true;
-}
-
-void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
-{
- ScriptReference ref;
- ref.script = blob;
- ref.location = location;
- ref.qualifier = qualifier;
-
- m_scripts << ref;
-}
-
-QQmlScriptData::QQmlScriptData()
- : typeNameCache(nullptr)
- , m_loaded(false)
-{
-}
-
-QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
-{
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
-
- if (m_precompiledScript->isESModule())
- return nullptr;
-
- auto qmlContextData = new QQmlContextData();
-
- qmlContextData->isInternal = true;
- qmlContextData->isJSContext = true;
- if (m_precompiledScript->isSharedLibrary())
- qmlContextData->isPragmaLibraryContext = true;
- else
- qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
- qmlContextData->baseUrl = url;
- qmlContextData->baseUrlString = urlString;
-
- // For backward compatibility, if there are no imports, we need to use the
- // imports from the parent context. See QTBUG-17518.
- if (!typeNameCache->isEmpty()) {
- qmlContextData->imports = typeNameCache;
- } else if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->imports = parentQmlContextData->imports;
- qmlContextData->importedScripts = parentQmlContextData->importedScripts;
- }
-
- if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->setParent(parentQmlContextData);
- } else {
- qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
- }
-
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
- QV4::Scope scope(v4);
- QV4::ScopedObject scriptsArray(scope);
- if (qmlContextData->importedScripts.isNullOrUndefined()) {
- scriptsArray = v4->newArrayObject(scripts.count());
- qmlContextData->importedScripts.set(v4, scriptsArray);
- } else {
- scriptsArray = qmlContextData->importedScripts.valueRef();
- }
- QV4::ScopedValue v(scope);
- for (int ii = 0; ii < scripts.count(); ++ii)
- scriptsArray->put(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData)));
-
- return qmlContextData;
-}
-
-QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
-{
- if (m_loaded)
- return m_value.value();
-
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
- QV4::Scope scope(v4);
-
- if (!hasEngine()) {
- addToEngine(parentQmlContextData->engine);
- addref();
- }
-
- QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData);
- QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
- if (qmlContextData)
- qmlExecutionContext =
- QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr);
-
- QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
- if (module) {
- if (qmlContextData) {
- module->d()->scope->outer.set(v4, qmlExecutionContext->d());
- qmlExecutionContext->d()->qml()->module.set(v4, module->d());
- }
-
- module->evaluate();
- }
-
- if (v4->hasException) {
- QQmlError error = v4->catchExceptionAsQmlError();
- if (error.isValid())
- QQmlEnginePrivate::get(v4)->warning(error);
- }
-
- QV4::ScopedValue value(scope);
- if (qmlContextData)
- value = qmlExecutionContext->d()->qml();
- else if (module)
- value = module->d();
-
- if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) {
- m_loaded = true;
- m_value.set(v4, value);
- }
-
- return value->asReturnedValue();
-}
-
-void QQmlScriptData::clear()
-{
- if (typeNameCache) {
- typeNameCache->release();
- typeNameCache = nullptr;
- }
-
- scripts.clear();
-
- // An addref() was made when the QQmlCleanup was added to the engine.
- release();
-}
-
-QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
- : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
- , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
-{
-}
-
-QQmlScriptBlob::~QQmlScriptBlob()
-{
-}
-
-QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
-{
- return m_scriptData;
-}
-
-void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
-{
- if (!disableDiskCache() || forceDiskCache()) {
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
- = QV4::ExecutableCompilationUnit::create();
- QString error;
- if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- initializeFromCompilationUnit(unit);
- return;
- } else {
- qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
- }
- }
-
- if (!data.exists()) {
- if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
- setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
- else
- setError(QQmlTypeLoader::tr("No such file or directory"));
- return;
- }
-
- QString error;
- QString source = data.readAll(&error);
- if (!error.isEmpty()) {
- setError(error);
- return;
- }
-
- QV4::CompiledData::CompilationUnit unit;
-
- if (m_isModule) {
- QList<QQmlJS::DiagnosticMessage> diagnostics;
- unit = QV4::Compiler::Codegen::compileModule(isDebugging(), urlString(), source,
- data.sourceTimeStamp(), &diagnostics);
- QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- } else {
- QmlIR::Document irUnit(isDebugging());
-
- irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
-
- QmlIR::ScriptDirectivesCollector collector(&irUnit);
- irUnit.jsParserEngine.setDirectives(&collector);
-
- QList<QQmlError> errors;
- irUnit.javaScriptCompilationUnit = QV4::Script::precompile(
- &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
- source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML);
-
- source.clear();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
-
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(irUnit);
- unit = std::move(irUnit.javaScriptCompilationUnit);
- }
-
- auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
-
- if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) {
- QString errorString;
- if (executableUnit->saveToDisk(url(), &errorString)) {
- QString error;
- if (!executableUnit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- // ignore error, keep using the in-memory compilation unit.
- }
- } else {
- qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of"
- << executableUnit->fileName() << "to disk:" << errorString;
- }
- }
-
- initializeFromCompilationUnit(executableUnit);
-}
-
-void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
-{
- initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
-}
-
-void QQmlScriptBlob::done()
-{
- if (isError())
- return;
-
- // Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
- const ScriptReference &script = m_scripts.at(ii);
- Q_ASSERT(script.script->isCompleteOrError());
- if (script.script->isError()) {
- QList<QQmlError> errors = script.script->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(script.location.line);
- error.setColumn(script.location.column);
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- if (!m_isModule) {
- m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
-
- QSet<QString> ns;
-
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const ScriptReference &script = m_scripts.at(scriptIndex);
-
- m_scriptData->scripts.append(script.script);
-
- if (!script.nameSpace.isNull()) {
- if (!ns.contains(script.nameSpace)) {
- ns.insert(script.nameSpace);
- m_scriptData->typeNameCache->add(script.nameSpace);
- }
- }
- m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
- }
-
- m_importCache.populateCache(m_scriptData->typeNameCache);
- }
- m_scripts.clear();
-}
-
-QString QQmlScriptBlob::stringAt(int index) const
-{
- return m_scriptData->m_precompiledScript->stringAt(index);
-}
-
-void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
-{
- ScriptReference ref;
- ref.script = blob;
- ref.location = location;
- ref.qualifier = qualifier;
- ref.nameSpace = nameSpace;
-
- m_scripts << ref;
-}
-
-void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
-{
- Q_ASSERT(!m_scriptData);
- m_scriptData.adopt(new QQmlScriptData());
- m_scriptData->url = finalUrl();
- m_scriptData->urlString = finalUrlString();
- m_scriptData->m_precompiledScript = unit;
-
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> script = m_scriptData->m_precompiledScript;
-
- if (!m_isModule) {
- QList<QQmlError> errors;
- for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = script->importAt(i);
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return;
- }
- }
- }
-
- auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
-
- v4->injectModule(unit);
-
- for (const QString &request: unit->moduleRequests()) {
- if (v4->moduleForUrl(QUrl(request), unit.data()))
- continue;
-
- const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
- addDependency(blob.data());
- scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
- }
-}
-
-QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
-: QQmlTypeLoader::Blob(url, QmldirFile, loader)
-{
-}
-
-const QString &QQmlQmldirData::content() const
-{
- return m_content;
-}
-
-const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *>::const_iterator it =
- m_imports.find(blob);
- if (it == m_imports.end())
- return nullptr;
- return *it;
-}
-
-void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
-{
- m_imports[blob] = import;
-}
-
-int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
- if (it == m_priorities.end())
- return 0;
- return *it;
-}
-
-void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
-{
- m_priorities[blob] = priority;
-}
-
-void QQmlQmldirData::dataReceived(const SourceCodeData &data)
-{
- QString error;
- m_content = data.readAll(&error);
- if (!error.isEmpty()) {
- setError(error);
- return;
- }
-}
-
-void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
-{
- Q_UNIMPLEMENTED();
-}
-
-QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
-{
- error->clear();
- if (hasInlineSourceCode)
- return inlineSourceCode;
-
- QFile f(fileInfo.absoluteFilePath());
- if (!f.open(QIODevice::ReadOnly)) {
- *error = f.errorString();
- return QString();
- }
-
- const qint64 fileSize = fileInfo.size();
-
- if (uchar *mappedData = f.map(0, fileSize)) {
- QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
- f.unmap(mappedData);
- return source;
- }
-
- QByteArray data(fileSize, Qt::Uninitialized);
- if (f.read(data.data(), data.length()) != data.length()) {
- *error = f.errorString();
- return QString();
- }
- return QString::fromUtf8(data);
-}
-
-QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
-{
- if (hasInlineSourceCode)
- return QDateTime();
-
- return fileInfo.lastModified();
-}
-
-bool QQmlDataBlob::SourceCodeData::exists() const
-{
- if (hasInlineSourceCode)
- return true;
- return fileInfo.exists();
-}
-
-bool QQmlDataBlob::SourceCodeData::isEmpty() const
-{
- if (hasInlineSourceCode)
- return inlineSourceCode.isEmpty();
- return fileInfo.size() == 0;
-}
-
QT_END_NAMESPACE
-
-#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 3330d52e56..5710bdba56 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -51,213 +51,25 @@
// We mean it.
//
+#include <private/qqmldatablob_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <QtQml/qtqmlglobal.h>
-#include <QtCore/qobject.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qcache.h>
-#if QT_CONFIG(qml_network)
-#include <QtNetwork/qnetworkreply.h>
-#endif
#include <QtQml/qqmlerror.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlfile.h>
-#include <QtQml/qqmlabstracturlinterceptor.h>
-
-#include <private/qhashedstring_p.h>
-#include <private/qqmlimport_p.h>
-#include <private/qqmlcleanup_p.h>
-#include <private/qqmldirparser_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qqmlirbuilder_p.h>
-#include <private/qv4executablecompilationunit_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4script_p.h>
+#include <QtCore/qcache.h>
+#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
-class QQmlScriptData;
class QQmlScriptBlob;
class QQmlQmldirData;
-class QQmlTypeLoader;
-class QQmlComponentPrivate;
class QQmlTypeData;
-class QQmlTypeLoader;
class QQmlExtensionInterface;
class QQmlProfiler;
-
-namespace QmlIR {
-struct Document;
-}
-
-class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
-{
-public:
- enum Status {
- Null, // Prior to QQmlTypeLoader::load()
- Loading, // Prior to data being received and dataReceived() being called
- WaitingForDependencies, // While there are outstanding addDependency()s
- ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
- Complete, // Finished
- Error // Error
- };
-
- enum Type { //Matched in QQmlAbstractUrlInterceptor
- QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
- JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
- QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
- };
-
- QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
- ~QQmlDataBlob() override;
-
- void startLoading();
-
- QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
-
- Type type() const;
-
- Status status() const;
- bool isNull() const;
- bool isLoading() const;
- bool isWaiting() const;
- bool isComplete() const;
- bool isError() const;
- bool isCompleteOrError() const;
-
- qreal progress() const;
-
- QUrl url() const;
- QString urlString() const;
- QUrl finalUrl() const;
- QString finalUrlString() const;
-
- QList<QQmlError> errors() const;
-
- class SourceCodeData {
- public:
- QString readAll(QString *error) const;
- QDateTime sourceTimeStamp() const;
- bool exists() const;
- bool isEmpty() const;
- private:
- friend class QQmlDataBlob;
- friend class QQmlTypeLoader;
- QString inlineSourceCode;
- QFileInfo fileInfo;
- bool hasInlineSourceCode = false;
- };
-
-protected:
- // Can be called from within callbacks
- void setError(const QQmlError &);
- void setError(const QList<QQmlError> &errors);
- void setError(const QQmlJS::DiagnosticMessage &error);
- void setError(const QVector<QQmlJS::DiagnosticMessage> &errors);
- void setError(const QString &description);
- void addDependency(QQmlDataBlob *);
-
- // Callbacks made in load thread
- virtual void dataReceived(const SourceCodeData &) = 0;
- virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
- virtual void done();
-#if QT_CONFIG(qml_network)
- virtual void networkError(QNetworkReply::NetworkError);
-#endif
- virtual void dependencyError(QQmlDataBlob *);
- virtual void dependencyComplete(QQmlDataBlob *);
- virtual void allDependenciesDone();
-
- // Callbacks made in main thread
- virtual void downloadProgressChanged(qreal);
- virtual void completed();
-
-protected:
- // Manager that is currently fetching data for me
- QQmlTypeLoader *m_typeLoader;
-
-private:
- friend class QQmlTypeLoader;
- friend class QQmlTypeLoaderThread;
-
- void tryDone();
- void cancelAllWaitingFor();
- void notifyAllWaitingOnMe();
- void notifyComplete(QQmlDataBlob *);
-
- struct ThreadData {
- inline ThreadData();
- inline QQmlDataBlob::Status status() const;
- inline void setStatus(QQmlDataBlob::Status);
- inline bool isAsync() const;
- inline void setIsAsync(bool);
- inline quint8 progress() const;
- inline void setProgress(quint8);
-
- private:
- QAtomicInt _p;
- };
- ThreadData m_data;
-
- // m_errors should *always* be written before the status is set to Error.
- // We use the status change as a memory fence around m_errors so that locking
- // isn't required. Once the status is set to Error (or Complete), m_errors
- // cannot be changed.
- QList<QQmlError> m_errors;
-
- Type m_type;
-
- QUrl m_url;
- QUrl m_finalUrl;
- mutable QString m_urlString;
- mutable QString m_finalUrlString;
-
- // List of QQmlDataBlob's that are waiting for me to complete.
- QList<QQmlDataBlob *> m_waitingOnMe;
-
- // List of QQmlDataBlob's that I am waiting for to complete.
- QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
-
- int m_redirectCount:30;
- bool m_inCallback:1;
- bool m_isDone:1;
-};
-
class QQmlTypeLoaderThread;
-
-class QQmlTypeLoaderQmldirContent
-{
-private:
- friend class QQmlTypeLoader;
-
- void setContent(const QString &location, const QString &content);
- void setError(const QQmlError &);
-
-public:
- QQmlTypeLoaderQmldirContent();
- QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
- QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
-
- bool hasContent() const { return m_hasContent; }
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
-
- QString typeNamespace() const;
-
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
-
- QString pluginLocation() const;
-
- bool designerSupported() const;
-
-private:
- QQmlDirParser m_parser;
- QString m_location;
- bool m_hasContent = false;
-};
+class QQmlEngine;
class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
{
@@ -293,6 +105,9 @@ public:
bool isDebugging() const;
+ static bool diskCacheDisabled();
+ static bool diskCacheForced();
+
QQmlImports m_importCache;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
@@ -418,209 +233,6 @@ private:
friend struct StaticLoader;
};
-class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
-public:
- struct TypeReference
- {
- TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
-
- QV4::CompiledData::Location location;
- QQmlType type;
- int majorVersion;
- int minorVersion;
- QQmlRefPointer<QQmlTypeData> typeData;
- QString prefix; // used by CompositeSingleton types
- QString qualifiedName() const;
- bool needsCreation;
- };
-
- struct ScriptReference
- {
- QV4::CompiledData::Location location;
- QString qualifier;
- QQmlRefPointer<QQmlScriptBlob> script;
- };
-
-private:
- friend class QQmlTypeLoader;
-
- QQmlTypeData(const QUrl &, QQmlTypeLoader *);
-
-public:
- ~QQmlTypeData() override;
-
- const QList<ScriptReference> &resolvedScripts() const;
-
- QV4::ExecutableCompilationUnit *compilationUnit() const;
-
- // Used by QQmlComponent to get notifications
- struct TypeDataCallback {
- virtual ~TypeDataCallback();
- virtual void typeDataProgress(QQmlTypeData *, qreal) {}
- virtual void typeDataReady(QQmlTypeData *) {}
- };
- void registerCallback(TypeDataCallback *);
- void unregisterCallback(TypeDataCallback *);
-
-protected:
- void done() override;
- void completed() override;
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
- void allDependenciesDone() override;
- void downloadProgressChanged(qreal) override;
-
- QString stringAt(int index) const override;
-
-private:
- bool tryLoadFromDiskCache();
- bool loadFromSource();
- void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
- void continueLoadFromIR();
- void resolveTypes();
- QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const;
- void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache);
- bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
- TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
- bool reportErrors = true,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
-
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
-
-
- SourceCodeData m_backupSourceCode; // used when cache verification fails.
- QScopedPointer<QmlIR::Document> m_document;
- QV4::CompiledData::TypeReferenceMap m_typeReferences;
-
- QList<ScriptReference> m_scripts;
-
- QSet<QString> m_namespaces;
- QList<TypeReference> m_compositeSingletons;
-
- // map from name index to resolved type
- // While this could be a hash, a map is chosen here to provide a stable
- // order, which is used to calculating a check-sum on dependent meta-objects.
- QMap<int, TypeReference> m_resolvedTypes;
- bool m_typesResolved:1;
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
-
- QList<TypeDataCallback *> m_callbacks;
-
- bool m_implicitImportLoaded;
- bool loadImplicitImport();
-};
-
-// QQmlScriptData instances are created, uninitialized, by the loader in the
-// load thread. The first time they are used by the VME, they are initialized which
-// creates their v8 objects and they are referenced and added to the engine's cleanup
-// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
-// reference that was created is released but final deletion only occurs once all the
-// references as released. This is all intended to ensure that the v8 resources are
-// only created and destroyed in the main thread :)
-class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlScriptData();
-
-public:
- QUrl url;
- QString urlString;
- QQmlTypeNameCache *typeNameCache;
- QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
-
- QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
-
-protected:
- void clear() override; // From QQmlCleanup
-
-private:
- friend class QQmlScriptBlob;
-
- void initialize(QQmlEngine *);
- QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
-
- bool m_loaded;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
- QV4::PersistentValue m_value;
-};
-
-class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
-
-public:
- ~QQmlScriptBlob() override;
-
- struct ScriptReference
- {
- QV4::CompiledData::Location location;
- QString qualifier;
- QString nameSpace;
- QQmlRefPointer<QQmlScriptBlob> script;
- };
-
- QQmlRefPointer<QQmlScriptData> scriptData() const;
-
-protected:
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
- void done() override;
-
- QString stringAt(int index) const override;
-
-private:
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
- void initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit);
-
- QList<ScriptReference> m_scripts;
- QQmlRefPointer<QQmlScriptData> m_scriptData;
- const bool m_isModule;
-};
-
-class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
-
-public:
- const QString &content() const;
-
- const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const;
- void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *);
-
- int priority(QQmlTypeLoader::Blob *) const;
- void setPriority(QQmlTypeLoader::Blob *, int);
-
-protected:
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
-
-private:
- QString m_content;
- QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *> m_imports;
- QHash<QQmlTypeLoader::Blob *, int> m_priorities;
-};
-
-
QT_END_NAMESPACE
#endif // QQMLTYPELOADER_P_H
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
new file mode 100644
index 0000000000..af97643163
--- /dev/null
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
+ : l(l)
+{
+}
+
+void QQmlTypeLoaderNetworkReplyProxy::finished()
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyFinished(reply);
+}
+
+void QQmlTypeLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyProgress(reply, bytesReceived, bytesTotal);
+}
+
+// This function is for when you want to shortcut the signals and call directly
+void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
+{
+ qint64 replySize = reply->size();
+ l->networkReplyProgress(reply, replySize, replySize);
+ l->networkReplyFinished(reply);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
new file mode 100644
index 0000000000..ed87a2b508
--- /dev/null
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPELOADERNETWORKREPLYPROXY_P_H
+#define QQMLTYPELOADERNETWORKREPLYPROXY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_REQUIRE_CONFIG(qml_network);
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QQmlTypeLoader;
+
+// This is a lame object that we need to ensure that slots connected to
+// QNetworkReply get called in the correct thread (the loader thread).
+// As QQmlTypeLoader lives in the main thread, and we can't use
+// Qt::DirectConnection connections from a QNetworkReply (because then
+// sender() wont work), we need to insert this object in the middle.
+class QQmlTypeLoaderNetworkReplyProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
+
+public slots:
+ void finished();
+ void downloadProgress(qint64, qint64);
+ void manualFinished(QNetworkReply*);
+
+private:
+ QQmlTypeLoader *l;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERNETWORKREPLYPROXY_P_H
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
new file mode 100644
index 0000000000..4aaa60f496
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <QtQml/qqmlerror.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
+{
+}
+
+bool QQmlTypeLoaderQmldirContent::hasError() const
+{
+ return m_parser.hasError();
+}
+
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
+{
+ QList<QQmlError> errors;
+ const QUrl url(uri);
+ for (const auto parseError : m_parser.errors(uri)) {
+ QQmlError error;
+ error.setUrl(url);
+ error.setLine(parseError.line);
+ error.setColumn(parseError.column);
+ error.setDescription(parseError.message);
+ errors.append(error);
+ }
+ return errors;
+}
+
+QString QQmlTypeLoaderQmldirContent::typeNamespace() const
+{
+ return m_parser.typeNamespace();
+}
+
+void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
+{
+ m_hasContent = true;
+ m_location = location;
+ m_parser.parse(content);
+}
+
+void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
+{
+ QQmlJS::DiagnosticMessage parseError;
+ parseError.line = error.line();
+ parseError.column = error.column();
+ parseError.message = error.description();
+ m_parser.setError(parseError);
+}
+
+QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
+{
+ return m_parser.components();
+}
+
+QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
+{
+ return m_parser.scripts();
+}
+
+QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
+{
+ return m_parser.plugins();
+}
+
+QString QQmlTypeLoaderQmldirContent::pluginLocation() const
+{
+ return m_location;
+}
+
+bool QQmlTypeLoaderQmldirContent::designerSupported() const
+{
+ return m_parser.designerSupported();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
new file mode 100644
index 0000000000..9e0a80cea8
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPELOADERQMLDIRCONTENT_P_H
+#define QQMLTYPELOADERQMLDIRCONTENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmldirparser_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlError;
+class QQmlTypeLoaderQmldirContent
+{
+private:
+ friend class QQmlTypeLoader;
+
+ void setContent(const QString &location, const QString &content);
+ void setError(const QQmlError &);
+
+public:
+ QQmlTypeLoaderQmldirContent();
+ QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
+ QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
+
+ bool hasContent() const { return m_hasContent; }
+ bool hasError() const;
+ QList<QQmlError> errors(const QString &uri) const;
+
+ QString typeNamespace() const;
+
+ QQmlDirComponents components() const;
+ QQmlDirScripts scripts() const;
+ QQmlDirPlugins plugins() const;
+
+ QString pluginLocation() const;
+
+ bool designerSupported() const;
+
+private:
+ QQmlDirParser m_parser;
+ QString m_location;
+ bool m_hasContent = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERQMLDIRCONTENT_P_H
diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp
new file mode 100644
index 0000000000..0e1cecd1e5
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderthread.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#if QT_CONFIG(qml_network)
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
+ : m_loader(loader)
+#if QT_CONFIG(qml_network)
+ , m_networkAccessManager(nullptr), m_networkReplyProxy(nullptr)
+#endif // qml_network
+{
+ // Do that after initializing all the members.
+ startup();
+}
+
+#if QT_CONFIG(qml_network)
+QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
+{
+ Q_ASSERT(isThisThread());
+ if (!m_networkAccessManager) {
+ m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
+ m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
+ }
+
+ return m_networkAccessManager;
+}
+
+QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
+{
+ Q_ASSERT(isThisThread());
+ Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
+ return m_networkReplyProxy;
+}
+#endif // qml_network
+
+void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
+{
+ b->addref();
+ callMethodInThread(&This::loadThread, b);
+}
+
+void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
+{
+ b->addref();
+ postMethodToThread(&This::loadThread, b);
+}
+
+void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
+void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b)
+{
+ b->addref();
+#if !QT_CONFIG(thread)
+ if (!isThisThread())
+ postMethodToThread(&This::callCompletedMain, b);
+#else
+ postMethodToMain(&This::callCompletedMain, b);
+#endif
+}
+
+void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
+{
+ b->addref();
+#if !QT_CONFIG(thread)
+ if (!isThisThread())
+ postMethodToThread(&This::callDownloadProgressChangedMain, b, p);
+#else
+ postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
+#endif
+}
+
+void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ callMethodInMain(&This::initializeEngineMain, iface, uri);
+}
+
+void QQmlTypeLoaderThread::shutdownThread()
+{
+#if QT_CONFIG(qml_network)
+ delete m_networkAccessManager;
+ m_networkAccessManager = nullptr;
+ delete m_networkReplyProxy;
+ m_networkReplyProxy = nullptr;
+#endif // qml_network
+}
+
+void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
+{
+ m_loader->loadThread(b);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
+{
+ m_loader->loadWithStaticDataThread(b, d);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ m_loader->loadWithCachedUnitThread(b, unit);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
+#endif
+ b->completed();
+ b->release();
+}
+
+void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
+ qPrintable(b->urlString()), p);
+#endif
+ b->downloadProgressChanged(p);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(m_loader->engine(), uri);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h
new file mode 100644
index 0000000000..67e47e86de
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderthread_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPELOADERTHREAD_P_H
+#define QQMLTYPELOADERTHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlthread_p.h>
+#include <private/qv4compileddata_p.h>
+
+#include <QtQml/qtqmlglobal.h>
+
+#if QT_CONFIG(qml_network)
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQmlDataBlob;
+class QQmlTypeLoader;
+class QQmlExtensionInterface;
+
+class QQmlTypeLoaderThread : public QQmlThread
+{
+ typedef QQmlTypeLoaderThread This;
+
+public:
+ QQmlTypeLoaderThread(QQmlTypeLoader *loader);
+#if QT_CONFIG(qml_network)
+ QNetworkAccessManager *networkAccessManager() const;
+ QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
+#endif // qml_network
+ void load(QQmlDataBlob *b);
+ void loadAsync(QQmlDataBlob *b);
+ void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
+ void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
+ void loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
+ void callCompleted(QQmlDataBlob *b);
+ void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
+ void initializeEngine(QQmlExtensionInterface *, const char *);
+
+protected:
+ void shutdownThread() override;
+
+private:
+ void loadThread(QQmlDataBlob *b);
+ void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
+ void callCompletedMain(QQmlDataBlob *b);
+ void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
+ void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
+
+ QQmlTypeLoader *m_loader;
+#if QT_CONFIG(qml_network)
+ mutable QNetworkAccessManager *m_networkAccessManager;
+ mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
+#endif // qml_network
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERTHREAD_P_H
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 57c4eec879..931f37b35a 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -42,6 +42,7 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qqmlmetaobject_p.h>
+#include <private/qqmltypedata_p.h>
#include <private/qjsvalue_p.h>
#include <private/qv4functionobject_p.h>
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 4838ef3814..2e213e7dc3 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -40,6 +40,7 @@
#include "qqmlbuiltinfunctions_p.h"
#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlfile.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlloggingcategory_p.h>