aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlmetatype.cpp22
-rw-r--r--src/qml/qml/qqmlmetatype_p.h3
-rw-r--r--src/qml/qml/qqmlprivate.h31
-rw-r--r--src/qml/qml/qqmltypeloader.cpp177
-rw-r--r--src/qml/qml/qqmltypeloader_p.h10
5 files changed, 205 insertions, 38 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 90d3ca3308..96894919a3 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -106,6 +106,7 @@ struct QQmlMetaTypeData
QBitArray lists;
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
+ QQmlPrivate::QmlUnitCacheLookupFunction lookupCachedQmlUnit;
QSet<QString> protectedNamespaces;
@@ -142,6 +143,7 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
}
QQmlMetaTypeData::QQmlMetaTypeData()
+ : lookupCachedQmlUnit(0)
{
}
@@ -1344,6 +1346,15 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
return index;
}
+int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
+{
+ if (hookRegistration.version > 0)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ data->lookupCachedQmlUnit = hookRegistration.lookupCachedQmlUnit;
+ return 0;
+}
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
@@ -1363,6 +1374,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
} else if (type == CompositeSingletonRegistration) {
return registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
+ } else if (type == QmlUnitCacheHookRegistration) {
+ return registerQmlUnitCacheHook(*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
}
return -1;
}
@@ -1887,4 +1900,13 @@ bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
return anchorLineCompareFunction(p1, p2);
}
+const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ if (data->lookupCachedQmlUnit)
+ return data->lookupCachedQmlUnit(uri);
+ return 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 019e6b8821..44ea7e284a 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -125,6 +125,8 @@ public:
static void setQQuickAnchorLineCompareFunction(CompareFunction);
static bool QQuickAnchorLineCompare(const void *p1, const void *p2);
+ static const QQmlPrivate::CachedQmlUnit *findCachedCompilationUnit(const QUrl &uri);
+
static bool namespaceContainsRegistrations(const QString &);
static void protectNamespace(const QString &);
@@ -240,6 +242,7 @@ private:
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &);
friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &);
+ friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &);
friend Q_QML_EXPORT void qmlClearTypeRegistrations();
QQmlType(int, const QQmlPrivate::RegisterInterface &);
QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &);
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 90e7961e6b..5460c99f1d 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -61,6 +61,22 @@
QT_BEGIN_NAMESPACE
+namespace QQmlPrivate {
+struct CachedQmlUnit;
+}
+
+namespace QV4 {
+struct ExecutionEngine;
+namespace CompiledData {
+struct QmlUnit;
+struct CompilationUnit;
+}
+typedef CompiledData::CompilationUnit *(*CompilationUnitFactoryFunction)();
+}
+namespace QmlIR {
+struct Document;
+typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *);
+}
typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *);
@@ -268,13 +284,26 @@ namespace QQmlPrivate
const char *typeName;
};
+ struct CachedQmlUnit {
+ const QV4::CompiledData::QmlUnit *qmlData;
+ QV4::CompilationUnitFactoryFunction createCompilationUnit;
+ QmlIR::IRLoaderFunction loadIR;
+ };
+
+ typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url);
+ struct RegisterQmlUnitCacheHook {
+ int version;
+ QmlUnitCacheLookupFunction lookupCachedQmlUnit;
+ };
+
enum RegistrationType {
TypeRegistration = 0,
InterfaceRegistration = 1,
AutoParentRegistration = 2,
SingletonRegistration = 3,
CompositeRegistration = 4,
- CompositeSingletonRegistration = 5
+ CompositeSingletonRegistration = 5,
+ QmlUnitCacheHookRegistration = 6
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 7f7ea1e5c1..c6693c2ae8 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -147,6 +147,7 @@ public:
void loadAsync(QQmlDataBlob *b);
void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
void callCompleted(QQmlDataBlob *b);
void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
void initializeEngine(QQmlExtensionInterface *, const char *);
@@ -157,6 +158,7 @@ protected:
private:
void loadThread(QQmlDataBlob *b);
void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
void callCompletedMain(QQmlDataBlob *b);
void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
@@ -777,6 +779,12 @@ void QQmlDataLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteA
postMethodToThread(&This::loadWithStaticDataThread, b, d);
}
+void QQmlDataLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
void QQmlDataLoaderThread::callCompleted(QQmlDataBlob *b)
{
b->addref();
@@ -815,6 +823,12 @@ void QQmlDataLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByte
b->release();
}
+void QQmlDataLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ m_loader->loadWithCachedUnitThread(b, unit);
+ b->release();
+}
+
void QQmlDataLoaderThread::callCompletedMain(QQmlDataBlob *b)
{
QML_MEMORY_SCOPE_URL(b->url());
@@ -965,6 +979,28 @@ void QQmlDataLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da
}
}
+void QQmlDataLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataLoader::loadWithUnitFcatory(%s, data): %s thread", qPrintable(blob->m_url.toString()),
+ m_thread->isThisThread()?"Compile":"Engine");
+#endif
+
+ blob->startLoading(this);
+
+ if (m_thread->isThisThread()) {
+ unlock();
+ loadWithCachedUnitThread(blob, unit);
+ lock();
+ } else {
+ unlock();
+ m_thread->loadWithCachedUnit(blob, unit);
+ lock();
+ if (!blob->isCompleteOrError())
+ blob->m_data.setIsAsync(true);
+ }
+}
+
void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data)
{
ASSERT_LOADTHREAD();
@@ -972,6 +1008,13 @@ void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArr
setData(blob, data);
}
+void QQmlDataLoader::loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ ASSERT_LOADTHREAD();
+
+ setCachedUnit(blob, unit);
+}
+
void QQmlDataLoader::loadThread(QQmlDataBlob *blob)
{
ASSERT_LOADTHREAD();
@@ -1165,6 +1208,24 @@ void QQmlDataLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d)
blob->tryDone();
}
+void QQmlDataLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+{
+ QML_MEMORY_SCOPE_URL(blob->url());
+ blob->m_inCallback = true;
+
+ blob->initializeFromCachedUnit(unit);
+
+ if (!blob->isError() && !blob->isWaiting())
+ blob->allDependenciesDone();
+
+ if (blob->status() != QQmlDataBlob::Error)
+ blob->m_data.setStatus(QQmlDataBlob::WaitingForDependencies);
+
+ blob->m_inCallback = false;
+
+ blob->tryDone();
+}
+
void QQmlDataLoader::shutdownThread()
{
if (!m_thread->isShutdown())
@@ -1539,7 +1600,11 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
- QQmlDataLoader::load(typeData, mode);
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) {
+ QQmlDataLoader::loadWithCachedUnit(typeData, cachedUnit);
+ } else {
+ QQmlDataLoader::load(typeData, mode);
+ }
}
typeData->addref();
@@ -1577,7 +1642,12 @@ QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &url)
if (!scriptBlob) {
scriptBlob = new QQmlScriptBlob(url, this);
m_scriptCache.insert(url, scriptBlob);
- QQmlDataLoader::load(scriptBlob);
+
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) {
+ QQmlDataLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
+ } else {
+ QQmlDataLoader::load(scriptBlob);
+ }
}
scriptBlob->addref();
@@ -2142,8 +2212,20 @@ void QQmlTypeData::dataReceived(const Data &data)
return;
}
- m_document->collectTypeReferences();
+ continueLoadFromIR();
+}
+void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
+{
+ QQmlEngine *qmlEngine = typeLoader()->engine();
+ m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
+ unit->loadIR(m_document.data(), unit);
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::continueLoadFromIR()
+{
+ m_document->collectTypeReferences();
m_importCache.setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
@@ -2192,7 +2274,6 @@ void QQmlTypeData::dataReceived(const Data &data)
return;
}
}
-
}
void QQmlTypeData::allDependenciesDone()
@@ -2570,7 +2651,6 @@ void QQmlScriptData::clear()
QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
: QQmlTypeLoader::Blob(url, JavaScriptFile, loader), m_scriptData(0)
-, m_irUnit(QV8Engine::getV4(loader->engine())->debugger != 0)
{
}
@@ -2591,12 +2671,10 @@ void QQmlScriptBlob::dataReceived(const Data &data)
{
QString source = QString::fromUtf8(data.data(), data.size());
- m_scriptData = new QQmlScriptData();
- m_scriptData->url = finalUrl();
- m_scriptData->urlString = finalUrlString();
-
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
+ QmlIR::Document irUnit(v4->debugger != 0);
QQmlError metaDataError;
- m_irUnit.extractScriptMetaData(source, &metaDataError);
+ irUnit.extractScriptMetaData(source, &metaDataError);
if (metaDataError.isValid()) {
metaDataError.setUrl(finalUrl());
setError(metaDataError);
@@ -2604,41 +2682,32 @@ void QQmlScriptBlob::dataReceived(const Data &data)
}
QList<QQmlError> errors;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- m_scriptData->m_precompiledScript = QV4::Script::precompile(&m_irUnit.jsModule, &m_irUnit.jsGenerator, v4, m_scriptData->url, source, &errors);
- if (m_scriptData->m_precompiledScript)
- m_scriptData->m_precompiledScript->ref();
+ QV4::CompiledData::CompilationUnit *unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors);
+ if (unit)
+ unit->ref();
source.clear();
if (!errors.isEmpty()) {
+ if (unit)
+ unit->deref();
setError(errors);
return;
}
+ irUnit.javaScriptCompilationUnit = unit;
- m_irUnit.javaScriptCompilationUnit = m_scriptData->m_precompiledScript;
QmlIR::QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(m_irUnit);
- if (m_scriptData->m_precompiledScript) {
- Q_ASSERT(!m_scriptData->m_precompiledScript->data);
- Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
- // The js unit owns the data and will free the qml unit.
- m_scriptData->m_precompiledScript->data = &qmlUnit->header;
- }
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(irUnit);
+ Q_ASSERT(!unit->data);
+ Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
+ // The js unit owns the data and will free the qml unit.
+ unit->data = &qmlUnit->header;
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ initializeFromCompilationUnit(unit);
+ unit->deref();
+}
- for (quint32 i = 0; i < qmlUnit->nImports; ++i) {
- const QV4::CompiledData::Import *import = qmlUnit->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;
- }
- }
+void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
+{
+ initializeFromCompilationUnit(unit->createCompilationUnit());
}
void QQmlScriptBlob::done()
@@ -2699,6 +2768,37 @@ void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledDat
m_scripts << ref;
}
+void QQmlScriptBlob::initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit)
+{
+ Q_ASSERT(!m_scriptData);
+ m_scriptData = new QQmlScriptData();
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->m_precompiledScript = unit;
+ if (m_scriptData->m_precompiledScript)
+ m_scriptData->m_precompiledScript->ref();
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ Q_ASSERT(m_scriptData->m_precompiledScript->data->flags & QV4::CompiledData::Unit::IsQml);
+ const QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<const QV4::CompiledData::QmlUnit*>(m_scriptData->m_precompiledScript->data);
+
+ QList<QQmlError> errors;
+ for (quint32 i = 0; i < qmlUnit->nImports; ++i) {
+ const QV4::CompiledData::Import *import = qmlUnit->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;
+ }
+ }
+}
+
QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
: QQmlTypeLoader::Blob(url, QmldirFile, loader), m_import(0), m_priority(0)
{
@@ -2734,6 +2834,11 @@ void QQmlQmldirData::dataReceived(const Data &data)
m_content = QString::fromUtf8(data.data(), data.size());
}
+void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
+{
+ Q_UNIMPLEMENTED();
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 43828c572e..b09ac15861 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -155,6 +155,7 @@ protected:
// Callbacks made in load thread
virtual void dataReceived(const Data &) = 0;
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0;
virtual void done();
virtual void networkError(QNetworkReply::NetworkError);
virtual void dependencyError(QQmlDataBlob *);
@@ -228,6 +229,7 @@ public:
void load(QQmlDataBlob *, Mode = PreferSynchronous);
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
+ void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
QQmlEngine *engine() const;
void initializeEngine(QQmlExtensionInterface *, const char *);
@@ -242,6 +244,7 @@ private:
void loadThread(QQmlDataBlob *);
void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
+ void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
void networkReplyFinished(QNetworkReply *);
void networkReplyProgress(QNetworkReply *, qint64, qint64);
@@ -250,6 +253,7 @@ private:
void setData(QQmlDataBlob *, const QByteArray &);
void setData(QQmlDataBlob *, QQmlFile *);
void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
+ void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
QQmlEngine *m_engine;
QQmlDataLoaderThread *m_thread;
@@ -447,12 +451,14 @@ protected:
virtual void done();
virtual void completed();
virtual void dataReceived(const Data &);
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit);
virtual void allDependenciesDone();
virtual void downloadProgressChanged(qreal);
virtual QString stringAt(int index) const;
private:
+ void continueLoadFromIR();
void resolveTypes();
void compile();
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref);
@@ -541,16 +547,17 @@ public:
protected:
virtual void dataReceived(const Data &);
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit);
virtual void done();
virtual QString stringAt(int index) const;
private:
virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);
+ void initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit);
QList<ScriptReference> m_scripts;
QQmlScriptData *m_scriptData;
- QmlIR::Document m_irUnit;
};
class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
@@ -571,6 +578,7 @@ public:
protected:
virtual void dataReceived(const Data &);
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*);
private:
QString m_content;