Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlscriptblob.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <private/qqmlengine_p.h>
5#include <private/qqmlirbuilder_p.h>
6#include <private/qqmlscriptblob_p.h>
7#include <private/qqmlscriptdata_p.h>
8#include <private/qqmlsourcecoordinate_p.h>
9#include <private/qqmlcontextdata_p.h>
10#include <private/qv4runtimecodegen_p.h>
11#include <private/qv4script_p.h>
12
13#include <QtCore/qloggingcategory.h>
14
15Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
16Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
17
19
21 : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
22 , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
23{
24}
25
29
30QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
31{
32 return m_scriptData;
33}
34
36{
37 return m_scriptData && !m_scriptData->m_value.isEmpty();
38}
39
41{
42 if (readCacheFile()) {
43 auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
45 if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
46 initializeFromCompilationUnit(std::move(unit));
47 return;
48 } else {
49 qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
50 }
51 }
52
53 if (!data.exists()) {
55 setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
56 else
57 setError(QQmlTypeLoader::tr("No such file or directory"));
58 return;
59 }
60
62 QString source = data.readAll(&error);
63 if (!error.isEmpty()) {
65 return;
66 }
67
68 QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
69
70 if (m_isModule) {
71 QList<QQmlJS::DiagnosticMessage> diagnostics;
73 data.sourceTimeStamp(), &diagnostics);
74 QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
75 if (!errors.isEmpty()) {
77 return;
78 }
79 } else {
81
82 irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
83
84 QmlIR::ScriptDirectivesCollector collector(&irUnit);
85 irUnit.jsParserEngine.setDirectives(&collector);
86
87 QList<QQmlError> errors;
88 irUnit.javaScriptCompilationUnit = QV4::Script::precompile(
89 &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
91
92 source.clear();
93 if (!errors.isEmpty()) {
95 return;
96 }
97
98 QmlIR::QmlUnitGenerator qmlGenerator;
99 qmlGenerator.generate(irUnit);
100 unit = std::move(irUnit.javaScriptCompilationUnit);
101 }
102
103 if (writeCacheFile()) {
104 QString errorString;
105 if (unit->saveToDisk(url(), &errorString)) {
107 if (!unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
108 // ignore error, keep using the in-memory compilation unit.
109 }
110 } else {
111 qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of"
112 << unit->fileName() << "to disk:" << errorString;
113 }
114 }
115
116 initializeFromCompilationUnit(std::move(unit));
117}
118
120{
121 initializeFromCompilationUnit(QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
122 cachedUnit->qmlData, cachedUnit->aotCompiledFunctions, urlString(), finalUrlString()));
123}
124
126{
127 if (isError())
128 return;
129
130 // Check all script dependencies for errors
131 for (int ii = 0; ii < m_scripts.size(); ++ii) {
132 const ScriptReference &script = m_scripts.at(ii);
134 if (script.script->isError()) {
135 QList<QQmlError> errors = script.script->errors();
137 error.setUrl(url());
138 error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
139 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
140 error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
143 return;
144 }
145 }
146
147 if (!m_isModule) {
149
150 QSet<QString> ns;
151
152 for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
153 const ScriptReference &script = m_scripts.at(scriptIndex);
154
155 m_scriptData->scripts.append(script.script);
156
157 if (!script.nameSpace.isNull()) {
158 if (!ns.contains(script.nameSpace)) {
159 ns.insert(script.nameSpace);
160 m_scriptData->typeNameCache->add(script.nameSpace);
161 }
162 }
163 m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
164 }
165
167 }
168 m_scripts.clear();
169}
170
172{
173 return m_scriptData->m_precompiledScript->stringAt(index);
174}
175
176void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
177{
179 ref.script = blob;
180 ref.location = location;
181 ref.qualifier = qualifier;
182 ref.nameSpace = nameSpace;
183
184 m_scripts << ref;
185}
186
187void QQmlScriptBlob::initializeFromCompilationUnit(
188 QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit)
189{
190 Q_ASSERT(!m_scriptData);
191 Q_ASSERT(unit);
192
193 m_scriptData.adopt(new QQmlScriptData());
194 m_scriptData->url = finalUrl();
195 m_scriptData->urlString = finalUrlString();
196 m_scriptData->m_precompiledScript = unit;
197
199
200 if (!m_isModule) {
201 QList<QQmlError> errors;
202 for (quint32 i = 0, count = unit->importCount(); i < count; ++i) {
203 const QV4::CompiledData::Import *import = unit->importAt(i);
204 if (!addImport(import, {}, &errors)) {
207 error.setUrl(m_importCache->baseUrl());
208 error.setLine(import->location.line());
209 error.setColumn(import->location.column());
210 errors.prepend(error); // put it back on the list after filling out information.
212 return;
213 }
214 }
215 }
216
217 const QStringList moduleRequests = unit->moduleRequests();
218 for (const QString &request: moduleRequests) {
219 const QUrl relativeRequest = QUrl(request);
220 if (m_typeLoader->injectedScript(relativeRequest))
221 continue;
222
223 const QUrl absoluteRequest = unit->finalUrl().resolved(relativeRequest);
224 QQmlRefPointer<QQmlScriptBlob> absoluteBlob = typeLoader()->getScript(absoluteRequest);
225 if (absoluteBlob->m_scriptData && absoluteBlob->m_scriptData->m_precompiledScript)
226 continue;
227
228 addDependency(absoluteBlob.data());
230 absoluteBlob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(),
231 /*namespace*/QString());
232 }
233}
234
235
244void QQmlScriptBlob::initializeFromNative(const QV4::Value &value)
245{
246 Q_ASSERT(!m_scriptData);
247 m_scriptData.adopt(new QQmlScriptData());
248 m_scriptData->url = finalUrl();
249 m_scriptData->urlString = finalUrlString();
250 m_scriptData->m_loaded = true;
251 m_scriptData->m_value.set(QQmlEnginePrivate::getV4Engine(typeLoader()->engine()), value);
253}
254
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
value_type takeFirst()
Definition qlist.h:566
void prepend(rvalue_ref t)
Definition qlist.h:473
bool isError() const
Returns true if the status is Error.
bool isCompleteOrError() const
Returns true if the status is Complete or Error.
void addDependency(QQmlDataBlob *)
Wait for blob to become complete or to error.
QList< QQmlError > errors() const
Return the errors on this blob.
QUrl url() const
Returns the physical url of the data.
QQmlTypeLoader * typeLoader() const
QUrl finalUrl() const
Returns the logical URL to be used for resolving further URLs referred to in the code.
QString finalUrlString() const
Returns the finalUrl() as a string.
void setError(const QQmlError &)
Mark this blob as having errors.
QString urlString() const
QQmlTypeLoader * m_typeLoader
static QList< QQmlError > qmlErrorFromDiagnostics(const QString &fileName, const QList< QQmlJS::DiagnosticMessage > &diagnosticMessages)
static QV4::ExecutionEngine * getV4Engine(QQmlEngine *e)
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
void populateCache(QQmlTypeNameCache *cache) const
void setBaseUrl(const QUrl &url, const QString &urlString=QString())
Sets the base URL to be used for all relative file imports added.
QUrl baseUrl() const
T * data() const
QQmlRefPointer< T > & adopt(T *)
Takes ownership of other.
void scriptImported(const QQmlRefPointer< QQmlScriptBlob > &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override
bool isNative() const
QQmlRefPointer< QQmlScriptData > scriptData() const
~QQmlScriptBlob() override
void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override
void dataReceived(const SourceCodeData &) override
Invoked when data for the blob is received.
QString stringAt(int index) const override
void done() override
Invoked once data has either been received or a network error occurred, and all dependencies are comp...
QVector< QQmlRefPointer< QQmlScriptBlob > > scripts
QQmlRefPointer< QQmlTypeNameCache > typeNameCache
bool addImport(const QV4::CompiledData::Import *import, QQmlImports::ImportFlags, QList< QQmlError > *errors)
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus
QQmlRefPointer< QQmlImports > m_importCache
The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
QQmlRefPointer< QQmlScriptBlob > injectedScript(const QUrl &relativeUrl)
QQmlRefPointer< QQmlScriptBlob > getScript(const QUrl &unNormalizedUrl)
Return a QQmlScriptBlob for url.
void add(const QHashedString &name, int sciptIndex=-1, const QHashedString &nameSpace=QHashedString())
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:994
\inmodule QtCore
Definition qurl.h:94
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2725
static QQmlRefPointer< QV4::CompiledData::CompilationUnit > compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList< QQmlJS::DiagnosticMessage > *diagnostics)
void set(ExecutionEngine *engine, const Value &value)
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLint location
GLuint index
[2]
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint ref
GLsizei GLsizei GLchar * source
GLsizei const GLchar *const * path
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
unsigned int quint32
Definition qtypes.h:50
QUrl url("example.com")
[constructor-url-reference]
QNetworkRequest request(url)
QJSEngine engine
[0]
QQmlRefPointer< QQmlScriptBlob > script
QV4::CompiledData::Location location
static QQmlRefPointer< QV4::CompiledData::CompilationUnit > precompile(QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, const QString &finalUrl, const QString &source, QList< QQmlError > *reportedErrors=nullptr, QV4::Compiler::ContextType contextType=QV4::Compiler::ContextType::Global)
void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher=QV4::CompiledData::DependentTypesHasher())