Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/qtdeclarative/src/qtdeclarative/src/qml/compiler/qv4compileddata.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||
2 | ** | - | ||||||||||||
3 | ** Copyright (C) 2016 The Qt Company Ltd. | - | ||||||||||||
4 | ** Contact: https://www.qt.io/licensing/ | - | ||||||||||||
5 | ** | - | ||||||||||||
6 | ** This file is part of the QtQml module of the Qt Toolkit. | - | ||||||||||||
7 | ** | - | ||||||||||||
8 | ** $QT_BEGIN_LICENSE:LGPL$ | - | ||||||||||||
9 | ** Commercial License Usage | - | ||||||||||||
10 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||
11 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||
12 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||
13 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||
14 | ** and conditions see https://www.qt.io/terms-conditions. For further | - | ||||||||||||
15 | ** information use the contact form at https://www.qt.io/contact-us. | - | ||||||||||||
16 | ** | - | ||||||||||||
17 | ** GNU Lesser General Public License Usage | - | ||||||||||||
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||
19 | ** General Public License version 3 as published by the Free Software | - | ||||||||||||
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | - | ||||||||||||
21 | ** packaging of this file. Please review the following information to | - | ||||||||||||
22 | ** ensure the GNU Lesser General Public License version 3 requirements | - | ||||||||||||
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | - | ||||||||||||
24 | ** | - | ||||||||||||
25 | ** GNU General Public License Usage | - | ||||||||||||
26 | ** Alternatively, this file may be used under the terms of the GNU | - | ||||||||||||
27 | ** General Public License version 2.0 or (at your option) the GNU General | - | ||||||||||||
28 | ** Public license version 3 or any later version approved by the KDE Free | - | ||||||||||||
29 | ** Qt Foundation. The licenses are as published by the Free Software | - | ||||||||||||
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | - | ||||||||||||
31 | ** included in the packaging of this file. Please review the following | - | ||||||||||||
32 | ** information to ensure the GNU General Public License requirements will | - | ||||||||||||
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | - | ||||||||||||
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | - | ||||||||||||
35 | ** | - | ||||||||||||
36 | ** $QT_END_LICENSE$ | - | ||||||||||||
37 | ** | - | ||||||||||||
38 | ****************************************************************************/ | - | ||||||||||||
39 | - | |||||||||||||
40 | #include "qv4compileddata_p.h" | - | ||||||||||||
41 | #include <private/qv4value_p.h> | - | ||||||||||||
42 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
43 | #include <private/qv4engine_p.h> | - | ||||||||||||
44 | #include <private/qv4function_p.h> | - | ||||||||||||
45 | #include <private/qv4objectproto_p.h> | - | ||||||||||||
46 | #include <private/qv4lookup_p.h> | - | ||||||||||||
47 | #include <private/qv4regexpobject_p.h> | - | ||||||||||||
48 | #include <private/qv4regexp_p.h> | - | ||||||||||||
49 | #include <private/qqmlpropertycache_p.h> | - | ||||||||||||
50 | #include <private/qqmltypeloader_p.h> | - | ||||||||||||
51 | #include <private/qqmlengine_p.h> | - | ||||||||||||
52 | #include <private/qv4vme_moth_p.h> | - | ||||||||||||
53 | #include "qv4compilationunitmapper_p.h" | - | ||||||||||||
54 | #include <QQmlPropertyMap> | - | ||||||||||||
55 | #include <QDateTime> | - | ||||||||||||
56 | #include <QFile> | - | ||||||||||||
57 | #include <QFileInfo> | - | ||||||||||||
58 | #include <QScopedValueRollback> | - | ||||||||||||
59 | #include <QStandardPaths> | - | ||||||||||||
60 | #include <QDir> | - | ||||||||||||
61 | #include <private/qv4identifiertable_p.h> | - | ||||||||||||
62 | #endif | - | ||||||||||||
63 | #include <private/qqmlirbuilder_p.h> | - | ||||||||||||
64 | #include <QCoreApplication> | - | ||||||||||||
65 | #include <QCryptographicHash> | - | ||||||||||||
66 | #include <QSaveFile> | - | ||||||||||||
67 | - | |||||||||||||
68 | // generated by qmake: | - | ||||||||||||
69 | #include "qml_compile_hash_p.h" | - | ||||||||||||
70 | - | |||||||||||||
71 | #include <algorithm> | - | ||||||||||||
72 | - | |||||||||||||
73 | QT_BEGIN_NAMESPACE | - | ||||||||||||
74 | - | |||||||||||||
75 | namespace QV4 { | - | ||||||||||||
76 | - | |||||||||||||
77 | namespace CompiledData { | - | ||||||||||||
78 | - | |||||||||||||
79 | static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version"); | - | ||||||||||||
80 | - | |||||||||||||
81 | CompilationUnit::CompilationUnit(const Unit *unitData) | - | ||||||||||||
82 | { | - | ||||||||||||
83 | data = unitData; | - | ||||||||||||
84 | } executed 2391957 times by 146 tests: end of block Executed by:
| 2391957 | ||||||||||||
85 | - | |||||||||||||
86 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
87 | CompilationUnit::~CompilationUnit() | - | ||||||||||||
88 | { | - | ||||||||||||
89 | unlink(); | - | ||||||||||||
90 | if (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) | - | ||||||||||||
91 | free(const_cast<Unit *>(data)); | - | ||||||||||||
92 | data = nullptr; | - | ||||||||||||
93 | } | - | ||||||||||||
94 | - | |||||||||||||
95 | QString CompilationUnit::localCacheFilePath(const QUrl &url) | - | ||||||||||||
96 | { | - | ||||||||||||
97 | const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url); | - | ||||||||||||
98 | const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix(); | - | ||||||||||||
99 | QCryptographicHash fileNameHash(QCryptographicHash::Sha1); | - | ||||||||||||
100 | fileNameHash.addData(localSourcePath.toUtf8()); | - | ||||||||||||
101 | QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/"); | - | ||||||||||||
102 | QDir::root().mkpath(directory); | - | ||||||||||||
103 | return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix; | - | ||||||||||||
104 | } | - | ||||||||||||
105 | - | |||||||||||||
106 | QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) | - | ||||||||||||
107 | { | - | ||||||||||||
108 | this->engine = engine; | - | ||||||||||||
109 | engine->compilationUnits.insert(this); | - | ||||||||||||
110 | - | |||||||||||||
111 | Q_ASSERT(!runtimeStrings); | - | ||||||||||||
112 | Q_ASSERT(data); | - | ||||||||||||
113 | runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*)); | - | ||||||||||||
114 | // memset the strings to 0 in case a GC run happens while we're within the loop below | - | ||||||||||||
115 | memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*)); | - | ||||||||||||
116 | for (uint i = 0; i < data->stringTableSize; ++i) | - | ||||||||||||
117 | runtimeStrings[i] = engine->newString(data->stringAt(i)); | - | ||||||||||||
118 | - | |||||||||||||
119 | runtimeRegularExpressions = new QV4::Value[data->regexpTableSize]; | - | ||||||||||||
120 | // memset the regexps to 0 in case a GC run happens while we're within the loop below | - | ||||||||||||
121 | memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value)); | - | ||||||||||||
122 | for (uint i = 0; i < data->regexpTableSize; ++i) { | - | ||||||||||||
123 | const CompiledData::RegExp *re = data->regexpAt(i); | - | ||||||||||||
124 | bool global = false; | - | ||||||||||||
125 | bool multiline = false; | - | ||||||||||||
126 | bool ignoreCase = false; | - | ||||||||||||
127 | if (re->flags & CompiledData::RegExp::RegExp_Global) | - | ||||||||||||
128 | global = true; | - | ||||||||||||
129 | if (re->flags & CompiledData::RegExp::RegExp_IgnoreCase) | - | ||||||||||||
130 | ignoreCase = true; | - | ||||||||||||
131 | if (re->flags & CompiledData::RegExp::RegExp_Multiline) | - | ||||||||||||
132 | multiline = true; | - | ||||||||||||
133 | runtimeRegularExpressions[i] = QV4::RegExp::create(engine, data->stringAt(re->stringIndex), ignoreCase, multiline, global); | - | ||||||||||||
134 | } | - | ||||||||||||
135 | - | |||||||||||||
136 | if (data->lookupTableSize) { | - | ||||||||||||
137 | runtimeLookups = new QV4::Lookup[data->lookupTableSize]; | - | ||||||||||||
138 | memset(runtimeLookups, 0, data->lookupTableSize * sizeof(QV4::Lookup)); | - | ||||||||||||
139 | const CompiledData::Lookup *compiledLookups = data->lookupTable(); | - | ||||||||||||
140 | for (uint i = 0; i < data->lookupTableSize; ++i) { | - | ||||||||||||
141 | QV4::Lookup *l = runtimeLookups + i; | - | ||||||||||||
142 | - | |||||||||||||
143 | Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags)); | - | ||||||||||||
144 | if (type == CompiledData::Lookup::Type_Getter) | - | ||||||||||||
145 | l->getter = QV4::Lookup::getterGeneric; | - | ||||||||||||
146 | else if (type == CompiledData::Lookup::Type_Setter) | - | ||||||||||||
147 | l->setter = QV4::Lookup::setterGeneric; | - | ||||||||||||
148 | else if (type == CompiledData::Lookup::Type_GlobalGetter) | - | ||||||||||||
149 | l->globalGetter = QV4::Lookup::globalGetterGeneric; | - | ||||||||||||
150 | l->nameIndex = compiledLookups[i].nameIndex; | - | ||||||||||||
151 | } | - | ||||||||||||
152 | } | - | ||||||||||||
153 | - | |||||||||||||
154 | if (data->jsClassTableSize) { | - | ||||||||||||
155 | runtimeClasses = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); | - | ||||||||||||
156 | // memset the regexps to 0 in case a GC run happens while we're within the loop below | - | ||||||||||||
157 | memset(runtimeClasses, 0, data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); | - | ||||||||||||
158 | for (uint i = 0; i < data->jsClassTableSize; ++i) { | - | ||||||||||||
159 | int memberCount = 0; | - | ||||||||||||
160 | const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); | - | ||||||||||||
161 | runtimeClasses[i] = engine->internalClasses(QV4::ExecutionEngine::Class_Object); | - | ||||||||||||
162 | for (int j = 0; j < memberCount; ++j, ++member) | - | ||||||||||||
163 | runtimeClasses[i] = runtimeClasses[i]->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); | - | ||||||||||||
164 | } | - | ||||||||||||
165 | } | - | ||||||||||||
166 | - | |||||||||||||
167 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN | - | ||||||||||||
168 | Value *bigEndianConstants = new Value[data->constantTableSize]; | - | ||||||||||||
169 | const quint64_le *littleEndianConstants = data->constants(); | - | ||||||||||||
170 | for (uint i = 0; i < data->constantTableSize; ++i) | - | ||||||||||||
171 | bigEndianConstants[i] = Value::fromReturnedValue(littleEndianConstants[i]); | - | ||||||||||||
172 | constants = bigEndianConstants; | - | ||||||||||||
173 | #else | - | ||||||||||||
174 | constants = reinterpret_cast<const Value*>(data->constants()); | - | ||||||||||||
175 | #endif | - | ||||||||||||
176 | - | |||||||||||||
177 | linkBackendToEngine(engine); | - | ||||||||||||
178 | - | |||||||||||||
179 | static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE"); | - | ||||||||||||
180 | if (showCode) { | - | ||||||||||||
181 | qDebug() << "=== Constant table"; | - | ||||||||||||
182 | Moth::dumpConstantTable(constants, data->constantTableSize); | - | ||||||||||||
183 | qDebug() << "=== String table"; | - | ||||||||||||
184 | for (uint i = 0; i < data->stringTableSize; ++i) | - | ||||||||||||
185 | qDebug() << " " << i << ":" << runtimeStrings[i]->toQString(); | - | ||||||||||||
186 | qDebug() << "=== Closure table"; | - | ||||||||||||
187 | for (uint i = 0; i < data->functionTableSize; ++i) | - | ||||||||||||
188 | qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString(); | - | ||||||||||||
189 | qDebug() << "root function at index " << (data->indexOfRootFunction != -1 ? data->indexOfRootFunction : 0); | - | ||||||||||||
190 | } | - | ||||||||||||
191 | - | |||||||||||||
192 | if (data->indexOfRootFunction != -1) | - | ||||||||||||
193 | return runtimeFunctions[data->indexOfRootFunction]; | - | ||||||||||||
194 | else | - | ||||||||||||
195 | return nullptr; | - | ||||||||||||
196 | } | - | ||||||||||||
197 | - | |||||||||||||
198 | void CompilationUnit::unlink() | - | ||||||||||||
199 | { | - | ||||||||||||
200 | if (engine) | - | ||||||||||||
201 | nextCompilationUnit.remove(); | - | ||||||||||||
202 | - | |||||||||||||
203 | if (isRegisteredWithEngine) { | - | ||||||||||||
204 | Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0)); | - | ||||||||||||
205 | if (qmlEngine) | - | ||||||||||||
206 | qmlEngine->unregisterInternalCompositeType(this); | - | ||||||||||||
207 | QQmlMetaType::unregisterInternalCompositeType(this); | - | ||||||||||||
208 | isRegisteredWithEngine = false; | - | ||||||||||||
209 | } | - | ||||||||||||
210 | - | |||||||||||||
211 | propertyCaches.clear(); | - | ||||||||||||
212 | - | |||||||||||||
213 | dependentScripts.clear(); | - | ||||||||||||
214 | - | |||||||||||||
215 | typeNameCache = nullptr; | - | ||||||||||||
216 | - | |||||||||||||
217 | qDeleteAll(resolvedTypes); | - | ||||||||||||
218 | resolvedTypes.clear(); | - | ||||||||||||
219 | - | |||||||||||||
220 | engine = nullptr; | - | ||||||||||||
221 | qmlEngine = nullptr; | - | ||||||||||||
222 | free(runtimeStrings); | - | ||||||||||||
223 | runtimeStrings = nullptr; | - | ||||||||||||
224 | delete [] runtimeLookups; | - | ||||||||||||
225 | runtimeLookups = nullptr; | - | ||||||||||||
226 | delete [] runtimeRegularExpressions; | - | ||||||||||||
227 | runtimeRegularExpressions = nullptr; | - | ||||||||||||
228 | free(runtimeClasses); | - | ||||||||||||
229 | runtimeClasses = nullptr; | - | ||||||||||||
230 | qDeleteAll(runtimeFunctions); | - | ||||||||||||
231 | runtimeFunctions.clear(); | - | ||||||||||||
232 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN | - | ||||||||||||
233 | delete [] constants; | - | ||||||||||||
234 | constants = nullptr; | - | ||||||||||||
235 | #endif | - | ||||||||||||
236 | } | - | ||||||||||||
237 | - | |||||||||||||
238 | void CompilationUnit::markObjects(QV4::MarkStack *markStack) | - | ||||||||||||
239 | { | - | ||||||||||||
240 | if (runtimeStrings) { | - | ||||||||||||
241 | for (uint i = 0; i < data->stringTableSize; ++i) | - | ||||||||||||
242 | if (runtimeStrings[i]) | - | ||||||||||||
243 | runtimeStrings[i]->mark(markStack); | - | ||||||||||||
244 | } | - | ||||||||||||
245 | if (runtimeRegularExpressions) { | - | ||||||||||||
246 | for (uint i = 0; i < data->regexpTableSize; ++i) | - | ||||||||||||
247 | runtimeRegularExpressions[i].mark(markStack); | - | ||||||||||||
248 | } | - | ||||||||||||
249 | if (runtimeClasses) { | - | ||||||||||||
250 | for (uint i = 0; i < data->jsClassTableSize; ++i) | - | ||||||||||||
251 | if (runtimeClasses[i]) | - | ||||||||||||
252 | runtimeClasses[i]->mark(markStack); | - | ||||||||||||
253 | } | - | ||||||||||||
254 | for (QV4::Function *f : qAsConst(runtimeFunctions)) | - | ||||||||||||
255 | if (f && f->internalClass) | - | ||||||||||||
256 | f->internalClass->mark(markStack); | - | ||||||||||||
257 | for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks)) | - | ||||||||||||
258 | if (c) | - | ||||||||||||
259 | c->mark(markStack); | - | ||||||||||||
260 | - | |||||||||||||
261 | if (runtimeLookups) { | - | ||||||||||||
262 | for (uint i = 0; i < data->lookupTableSize; ++i) | - | ||||||||||||
263 | runtimeLookups[i].markObjects(markStack); | - | ||||||||||||
264 | } | - | ||||||||||||
265 | } | - | ||||||||||||
266 | - | |||||||||||||
267 | IdentifierHash CompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex) | - | ||||||||||||
268 | { | - | ||||||||||||
269 | IdentifierHash namedObjectCache(engine); | - | ||||||||||||
270 | const CompiledData::Object *component = data->objectAt(componentObjectIndex); | - | ||||||||||||
271 | const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable(); | - | ||||||||||||
272 | for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) { | - | ||||||||||||
273 | const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr); | - | ||||||||||||
274 | namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id); | - | ||||||||||||
275 | } | - | ||||||||||||
276 | return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); | - | ||||||||||||
277 | } | - | ||||||||||||
278 | - | |||||||||||||
279 | void CompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine) | - | ||||||||||||
280 | { | - | ||||||||||||
281 | this->qmlEngine = qmlEngine; | - | ||||||||||||
282 | - | |||||||||||||
283 | // Add to type registry of composites | - | ||||||||||||
284 | if (propertyCaches.needsVMEMetaObject(/*root object*/0)) { | - | ||||||||||||
285 | QQmlMetaType::registerInternalCompositeType(this); | - | ||||||||||||
286 | qmlEngine->registerInternalCompositeType(this); | - | ||||||||||||
287 | } else { | - | ||||||||||||
288 | const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); | - | ||||||||||||
289 | auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); | - | ||||||||||||
290 | Q_ASSERT(typeRef); | - | ||||||||||||
291 | if (typeRef->compilationUnit) { | - | ||||||||||||
292 | metaTypeId = typeRef->compilationUnit->metaTypeId; | - | ||||||||||||
293 | listMetaTypeId = typeRef->compilationUnit->listMetaTypeId; | - | ||||||||||||
294 | } else { | - | ||||||||||||
295 | metaTypeId = typeRef->type.typeId(); | - | ||||||||||||
296 | listMetaTypeId = typeRef->type.qListTypeId(); | - | ||||||||||||
297 | } | - | ||||||||||||
298 | } | - | ||||||||||||
299 | - | |||||||||||||
300 | // Collect some data for instantiation later. | - | ||||||||||||
301 | int bindingCount = 0; | - | ||||||||||||
302 | int parserStatusCount = 0; | - | ||||||||||||
303 | int objectCount = 0; | - | ||||||||||||
304 | for (quint32 i = 0; i < data->nObjects; ++i) { | - | ||||||||||||
305 | const QV4::CompiledData::Object *obj = data->objectAt(i); | - | ||||||||||||
306 | bindingCount += obj->nBindings; | - | ||||||||||||
307 | if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { | - | ||||||||||||
308 | if (typeRef->type.isValid()) { | - | ||||||||||||
309 | if (typeRef->type.parserStatusCast() != -1) | - | ||||||||||||
310 | ++parserStatusCount; | - | ||||||||||||
311 | } | - | ||||||||||||
312 | ++objectCount; | - | ||||||||||||
313 | if (typeRef->compilationUnit) { | - | ||||||||||||
314 | bindingCount += typeRef->compilationUnit->totalBindingsCount; | - | ||||||||||||
315 | parserStatusCount += typeRef->compilationUnit->totalParserStatusCount; | - | ||||||||||||
316 | objectCount += typeRef->compilationUnit->totalObjectCount; | - | ||||||||||||
317 | } | - | ||||||||||||
318 | } | - | ||||||||||||
319 | } | - | ||||||||||||
320 | - | |||||||||||||
321 | totalBindingsCount = bindingCount; | - | ||||||||||||
322 | totalParserStatusCount = parserStatusCount; | - | ||||||||||||
323 | totalObjectCount = objectCount; | - | ||||||||||||
324 | } | - | ||||||||||||
325 | - | |||||||||||||
326 | bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const | - | ||||||||||||
327 | { | - | ||||||||||||
328 | if (!dependencyHasher) { | - | ||||||||||||
329 | for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) { | - | ||||||||||||
330 | if (data->dependencyMD5Checksum[i] != 0) | - | ||||||||||||
331 | return false; | - | ||||||||||||
332 | } | - | ||||||||||||
333 | return true; | - | ||||||||||||
334 | } | - | ||||||||||||
335 | QCryptographicHash hash(QCryptographicHash::Md5); | - | ||||||||||||
336 | if (!dependencyHasher(&hash)) | - | ||||||||||||
337 | return false; | - | ||||||||||||
338 | QByteArray checksum = hash.result(); | - | ||||||||||||
339 | Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum)); | - | ||||||||||||
340 | return memcmp(data->dependencyMD5Checksum, checksum.constData(), | - | ||||||||||||
341 | sizeof(data->dependencyMD5Checksum)) == 0; | - | ||||||||||||
342 | } | - | ||||||||||||
343 | - | |||||||||||||
344 | bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString) | - | ||||||||||||
345 | { | - | ||||||||||||
346 | if (!QQmlFile::isLocalFile(url)) { | - | ||||||||||||
347 | *errorString = QStringLiteral("File has to be a local file."); | - | ||||||||||||
348 | return false; | - | ||||||||||||
349 | } | - | ||||||||||||
350 | - | |||||||||||||
351 | const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url); | - | ||||||||||||
352 | QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper()); | - | ||||||||||||
353 | - | |||||||||||||
354 | QString cachePath = sourcePath + QLatin1Char('c'); | - | ||||||||||||
355 | if (!QFile::exists(cachePath)) | - | ||||||||||||
356 | cachePath = localCacheFilePath(url); | - | ||||||||||||
357 | - | |||||||||||||
358 | CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString); | - | ||||||||||||
359 | if (!mappedUnit) | - | ||||||||||||
360 | return false; | - | ||||||||||||
361 | - | |||||||||||||
362 | const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr; | - | ||||||||||||
363 | QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit); | - | ||||||||||||
364 | - | |||||||||||||
365 | if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { | - | ||||||||||||
366 | *errorString = QStringLiteral("QML source file has moved to a different location."); | - | ||||||||||||
367 | return false; | - | ||||||||||||
368 | } | - | ||||||||||||
369 | - | |||||||||||||
370 | dataPtrChange.commit(); | - | ||||||||||||
371 | free(const_cast<Unit*>(oldDataPtr)); | - | ||||||||||||
372 | backingFile.reset(cacheFile.take()); | - | ||||||||||||
373 | return true; | - | ||||||||||||
374 | } | - | ||||||||||||
375 | - | |||||||||||||
376 | void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine) | - | ||||||||||||
377 | { | - | ||||||||||||
378 | runtimeFunctions.resize(data->functionTableSize); | - | ||||||||||||
379 | for (int i = 0 ;i < runtimeFunctions.size(); ++i) { | - | ||||||||||||
380 | const QV4::CompiledData::Function *compiledFunction = data->functionAt(i); | - | ||||||||||||
381 | runtimeFunctions[i] = new QV4::Function(engine, this, compiledFunction); | - | ||||||||||||
382 | } | - | ||||||||||||
383 | - | |||||||||||||
384 | Scope scope(engine); | - | ||||||||||||
385 | Scoped<InternalClass> ic(scope); | - | ||||||||||||
386 | - | |||||||||||||
387 | runtimeBlocks.resize(data->blockTableSize); | - | ||||||||||||
388 | for (int i = 0 ;i < runtimeBlocks.size(); ++i) { | - | ||||||||||||
389 | const QV4::CompiledData::Block *compiledBlock = data->blockAt(i); | - | ||||||||||||
390 | ic = engine->internalClasses(EngineBase::Class_CallContext); | - | ||||||||||||
391 | - | |||||||||||||
392 | // first locals | - | ||||||||||||
393 | const quint32_le *localsIndices = compiledBlock->localsTable(); | - | ||||||||||||
394 | for (quint32 i = 0; i < compiledBlock->nLocals; ++i) | - | ||||||||||||
395 | ic = ic->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); | - | ||||||||||||
396 | runtimeBlocks[i] = ic->d(); | - | ||||||||||||
397 | } | - | ||||||||||||
398 | } | - | ||||||||||||
399 | - | |||||||||||||
400 | #endif // V4_BOOTSTRAP | - | ||||||||||||
401 | - | |||||||||||||
402 | #if defined(V4_BOOTSTRAP) | - | ||||||||||||
403 | bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString) | - | ||||||||||||
404 | #else | - | ||||||||||||
405 | bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) | - | ||||||||||||
406 | #endif | - | ||||||||||||
407 | { | - | ||||||||||||
408 | errorString->clear(); | - | ||||||||||||
409 | - | |||||||||||||
410 | #if !defined(V4_BOOTSTRAP) | - | ||||||||||||
411 | if (data->sourceTimeStamp == 0) { | - | ||||||||||||
412 | *errorString = QStringLiteral("Missing time stamp for source file"); | - | ||||||||||||
413 | return false; | - | ||||||||||||
414 | } | - | ||||||||||||
415 | - | |||||||||||||
416 | if (!QQmlFile::isLocalFile(unitUrl)) { | - | ||||||||||||
417 | *errorString = QStringLiteral("File has to be a local file."); | - | ||||||||||||
418 | return false; | - | ||||||||||||
419 | } | - | ||||||||||||
420 | const QString outputFileName = localCacheFilePath(unitUrl); | - | ||||||||||||
421 | #endif | - | ||||||||||||
422 | - | |||||||||||||
423 | #if QT_CONFIG(temporaryfile) | - | ||||||||||||
424 | // Foo.qml -> Foo.qmlc | - | ||||||||||||
425 | QSaveFile cacheFile(outputFileName); | - | ||||||||||||
426 | if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
| 0-2726 | ||||||||||||
427 | *errorString = cacheFile.errorString(); | - | ||||||||||||
428 | return false; never executed: return false; | 0 | ||||||||||||
429 | } | - | ||||||||||||
430 | - | |||||||||||||
431 | QByteArray modifiedUnit; | - | ||||||||||||
432 | modifiedUnit.resize(data->unitSize); | - | ||||||||||||
433 | memcpy(modifiedUnit.data(), data, data->unitSize); | - | ||||||||||||
434 | const char *dataPtr = modifiedUnit.data(); | - | ||||||||||||
435 | Unit *unitPtr; | - | ||||||||||||
436 | memcpy(&unitPtr, &dataPtr, sizeof(unitPtr)); | - | ||||||||||||
437 | unitPtr->flags |= Unit::StaticData; | - | ||||||||||||
438 | - | |||||||||||||
439 | qint64 headerWritten = cacheFile.write(modifiedUnit); | - | ||||||||||||
440 | if (headerWritten != modifiedUnit.size()) {
| 0-2726 | ||||||||||||
441 | *errorString = cacheFile.errorString(); | - | ||||||||||||
442 | return false; never executed: return false; | 0 | ||||||||||||
443 | } | - | ||||||||||||
444 | - | |||||||||||||
445 | if (!cacheFile.commit()) {
| 0-2726 | ||||||||||||
446 | *errorString = cacheFile.errorString(); | - | ||||||||||||
447 | return false; never executed: return false; | 0 | ||||||||||||
448 | } | - | ||||||||||||
449 | - | |||||||||||||
450 | return true; executed 2726 times by 125 tests: return true; Executed by:
| 2726 | ||||||||||||
451 | #else | - | ||||||||||||
452 | Q_UNUSED(outputFileName) | - | ||||||||||||
453 | *errorString = QStringLiteral("features.temporaryfile is disabled."); | - | ||||||||||||
454 | return false; | - | ||||||||||||
455 | #endif // QT_CONFIG(temporaryfile) | - | ||||||||||||
456 | } | - | ||||||||||||
457 | - | |||||||||||||
458 | Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) | - | ||||||||||||
459 | { | - | ||||||||||||
460 | if (!irDocument->javaScriptCompilationUnit->data)
| 24-48529 | ||||||||||||
461 | return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable); executed 48529 times by 141 tests: return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable); Executed by:
| 48529 | ||||||||||||
462 | - | |||||||||||||
463 | QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit; | - | ||||||||||||
464 | QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(compilationUnit->data); | - | ||||||||||||
465 | auto ensureWritableUnit = [&jsUnit, &compilationUnit]() { | - | ||||||||||||
466 | if (jsUnit == compilationUnit->data) {
| 4-24 | ||||||||||||
467 | char *unitCopy = (char*)malloc(jsUnit->unitSize); | - | ||||||||||||
468 | memcpy(unitCopy, jsUnit, jsUnit->unitSize); | - | ||||||||||||
469 | jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy); | - | ||||||||||||
470 | } executed 24 times by 1 test: end of block Executed by:
| 24 | ||||||||||||
471 | }; executed 28 times by 1 test: end of block Executed by:
| 28 | ||||||||||||
472 | - | |||||||||||||
473 | QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable; | - | ||||||||||||
474 | - | |||||||||||||
475 | if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) {
| 0-24 | ||||||||||||
476 | ensureWritableUnit(); | - | ||||||||||||
477 | jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName); | - | ||||||||||||
478 | jsUnit->finalUrlIndex = stringTable.registerString(irDocument->jsModule.finalUrl); | - | ||||||||||||
479 | } executed 24 times by 1 test: end of block Executed by:
| 24 | ||||||||||||
480 | - | |||||||||||||
481 | // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example) | - | ||||||||||||
482 | // and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize | - | ||||||||||||
483 | // the string table. | - | ||||||||||||
484 | QVector<quint32> changedSignals; | - | ||||||||||||
485 | QVector<QQmlJS::AST::FormalParameterList*> changedSignalParameters; | - | ||||||||||||
486 | for (QmlIR::Object *o: qAsConst(irDocument->objects)) { | - | ||||||||||||
487 | for (QmlIR::Binding *binding = o->firstBinding(); binding; binding = binding->next) {
| 38-62 | ||||||||||||
488 | if (!(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression))
| 10-52 | ||||||||||||
489 | continue; executed 52 times by 1 test: continue; Executed by:
| 52 | ||||||||||||
490 | - | |||||||||||||
491 | quint32 functionIndex = binding->value.compiledScriptIndex; | - | ||||||||||||
492 | QmlIR::CompiledFunctionOrExpression *foe = o->functionsAndExpressions->slowAt(functionIndex); | - | ||||||||||||
493 | if (!foe)
| 0-10 | ||||||||||||
494 | continue; never executed: continue; | 0 | ||||||||||||
495 | - | |||||||||||||
496 | // save absolute index | - | ||||||||||||
497 | changedSignals << o->runtimeFunctionIndices.at(functionIndex); | - | ||||||||||||
498 | - | |||||||||||||
499 | Q_ASSERT(foe->node); | - | ||||||||||||
500 | Q_ASSERT(QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)); | - | ||||||||||||
501 | - | |||||||||||||
502 | QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals; | - | ||||||||||||
503 | changedSignalParameters << parameters; | - | ||||||||||||
504 | - | |||||||||||||
505 | if (parameters) {
| 4-6 | ||||||||||||
506 | const QStringList formals = parameters->formals(); | - | ||||||||||||
507 | for (const QString &arg : formals) | - | ||||||||||||
508 | stringTable.registerString(arg); executed 4 times by 1 test: stringTable.registerString(arg); Executed by:
| 4 | ||||||||||||
509 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||
510 | } executed 10 times by 1 test: end of block Executed by:
| 10 | ||||||||||||
511 | } executed 38 times by 1 test: end of block Executed by:
| 38 | ||||||||||||
512 | - | |||||||||||||
513 | QVector<quint32> signalParameterNameTable; | - | ||||||||||||
514 | quint32 signalParameterNameTableOffset = jsUnit->unitSize; | - | ||||||||||||
515 | - | |||||||||||||
516 | // Update signal signatures | - | ||||||||||||
517 | if (!changedSignals.isEmpty()) {
| 8-16 | ||||||||||||
518 | if (jsUnit == compilationUnit->data) {
| 0-8 | ||||||||||||
519 | char *unitCopy = (char*)malloc(jsUnit->unitSize); | - | ||||||||||||
520 | memcpy(unitCopy, jsUnit, jsUnit->unitSize); | - | ||||||||||||
521 | jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy); | - | ||||||||||||
522 | } never executed: end of block | 0 | ||||||||||||
523 | - | |||||||||||||
524 | for (int i = 0; i < changedSignals.count(); ++i) {
| 8-10 | ||||||||||||
525 | const uint functionIndex = changedSignals.at(i); | - | ||||||||||||
526 | // The data is now read-write due to the copy above, so the const_cast is ok. | - | ||||||||||||
527 | QV4::CompiledData::Function *function = const_cast<QV4::CompiledData::Function *>(jsUnit->functionAt(functionIndex)); | - | ||||||||||||
528 | Q_ASSERT(function->nFormals == quint32(0)); | - | ||||||||||||
529 | - | |||||||||||||
530 | function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex]; | - | ||||||||||||
531 | - | |||||||||||||
532 | if (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i)) {
| 4-6 | ||||||||||||
533 | const QStringList formals = parameters->formals(); | - | ||||||||||||
534 | for (const QString &arg : formals) | - | ||||||||||||
535 | signalParameterNameTable.append(stringTable.getStringId(arg)); executed 4 times by 1 test: signalParameterNameTable.append(stringTable.getStringId(arg)); Executed by:
| 4 | ||||||||||||
536 | - | |||||||||||||
537 | function->nFormals = formals.size(); | - | ||||||||||||
538 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||
539 | function->length = function->nFormals; | - | ||||||||||||
540 | - | |||||||||||||
541 | signalParameterNameTableOffset += function->nFormals * sizeof(quint32); | - | ||||||||||||
542 | } executed 10 times by 1 test: end of block Executed by:
| 10 | ||||||||||||
543 | } executed 8 times by 1 test: end of block Executed by:
| 8 | ||||||||||||
544 | - | |||||||||||||
545 | if (!signalParameterNameTable.isEmpty()) {
| 4-20 | ||||||||||||
546 | ensureWritableUnit(); | - | ||||||||||||
547 | Q_ASSERT(jsUnit != compilationUnit->data); | - | ||||||||||||
548 | const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32); | - | ||||||||||||
549 | uint newSize = jsUnit->unitSize + signalParameterTableSize; | - | ||||||||||||
550 | const uint oldSize = jsUnit->unitSize; | - | ||||||||||||
551 | char *unitWithSignalParameters = (char*)realloc(jsUnit, newSize); | - | ||||||||||||
552 | memcpy(unitWithSignalParameters + oldSize, signalParameterNameTable.constData(), signalParameterTableSize); | - | ||||||||||||
553 | jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitWithSignalParameters); | - | ||||||||||||
554 | jsUnit->unitSize = newSize; | - | ||||||||||||
555 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||
556 | - | |||||||||||||
557 | if (jsUnit != compilationUnit->data)
| 0-24 | ||||||||||||
558 | jsUnit->flags &= ~QV4::CompiledData::Unit::StaticData; executed 24 times by 1 test: jsUnit->flags &= ~QV4::CompiledData::Unit::StaticData; Executed by:
| 24 | ||||||||||||
559 | - | |||||||||||||
560 | return jsUnit; executed 24 times by 1 test: return jsUnit; Executed by:
| 24 | ||||||||||||
561 | } | - | ||||||||||||
562 | - | |||||||||||||
563 | QString Binding::valueAsString(const Unit *unit) const | - | ||||||||||||
564 | { | - | ||||||||||||
565 | switch (type) { | - | ||||||||||||
566 | case Type_Script: executed 4414 times by 19 tests: case Type_Script: Executed by:
| 4414 | ||||||||||||
567 | case Type_String: executed 272438 times by 118 tests: case Type_String: Executed by:
| 272438 | ||||||||||||
568 | return unit->stringAt(stringIndex); executed 276852 times by 120 tests: return unit->stringAt(stringIndex); Executed by:
| 276852 | ||||||||||||
569 | case Type_Boolean: never executed: case Type_Boolean: | 0 | ||||||||||||
570 | return value.b ? QStringLiteral("true") : QStringLiteral("false"); never executed: return value.b ? ([]() noexcept -> QString { enum { Size = sizeof(u"" "true")/2 - 1 }; static const QStaticStringData<Size> qstring_literal = { { { { -1 } }, Size, 0, 0, sizeof(QStringData) }, u"" "true" }; QStringDataPtr holder = { qstring_literal.data_p...static const QStaticStringData<Size> qstring_literal = { { { { -1 } }, Size, 0, 0, sizeof(QStringData) }, u"" "false" }; QStringDataPtr holder = { qstring_literal.data_ptr() }; const QString qstring_literal_temp(holder); return qstring_literal_temp; }()); never executed: return qstring_literal_temp; never executed: return qstring_literal_temp; | 0 | ||||||||||||
571 | case Type_Number: executed 184 times by 4 tests: case Type_Number: Executed by:
| 184 | ||||||||||||
572 | return QString::number(valueAsNumber()); executed 184 times by 4 tests: return QString::number(valueAsNumber()); Executed by:
| 184 | ||||||||||||
573 | case Type_Invalid: never executed: case Type_Invalid: | 0 | ||||||||||||
574 | return QString(); never executed: return QString(); | 0 | ||||||||||||
575 | #if !QT_CONFIG(translation) | - | ||||||||||||
576 | case Type_TranslationById: | - | ||||||||||||
577 | case Type_Translation: | - | ||||||||||||
578 | return unit->stringAt(stringIndex); | - | ||||||||||||
579 | #else | - | ||||||||||||
580 | case Type_TranslationById: { executed 8 times by 3 tests: case Type_TranslationById: Executed by:
| 8 | ||||||||||||
581 | QByteArray id = unit->stringAt(stringIndex).toUtf8(); | - | ||||||||||||
582 | return qtTrId(id.constData(), value.translationData.number); executed 8 times by 3 tests: return qtTrId(id.constData(), value.translationData.number); Executed by:
| 8 | ||||||||||||
583 | } | - | ||||||||||||
584 | case Type_Translation: { executed 42 times by 7 tests: case Type_Translation: Executed by:
| 42 | ||||||||||||
585 | // This code must match that in the qsTr() implementation | - | ||||||||||||
586 | const QString &path = unit->stringAt(unit->sourceFileIndex); | - | ||||||||||||
587 | int lastSlash = path.lastIndexOf(QLatin1Char('/')); | - | ||||||||||||
588 | QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
| 2-40 | ||||||||||||
589 | : QStringRef(); | - | ||||||||||||
590 | QByteArray contextUtf8 = context.toUtf8(); | - | ||||||||||||
591 | QByteArray comment = unit->stringAt(value.translationData.commentIndex).toUtf8(); | - | ||||||||||||
592 | QByteArray text = unit->stringAt(stringIndex).toUtf8(); | - | ||||||||||||
593 | return QCoreApplication::translate(contextUtf8.constData(), text.constData(), executed 42 times by 7 tests: return QCoreApplication::translate(contextUtf8.constData(), text.constData(), comment.constData(), value.translationData.number); Executed by:
| 42 | ||||||||||||
594 | comment.constData(), value.translationData.number); executed 42 times by 7 tests: return QCoreApplication::translate(contextUtf8.constData(), text.constData(), comment.constData(), value.translationData.number); Executed by:
| 42 | ||||||||||||
595 | } | - | ||||||||||||
596 | #endif | - | ||||||||||||
597 | default: never executed: default: | 0 | ||||||||||||
598 | break; never executed: break; | 0 | ||||||||||||
599 | } | - | ||||||||||||
600 | return QString(); never executed: return QString(); | 0 | ||||||||||||
601 | } | - | ||||||||||||
602 | - | |||||||||||||
603 | //reverse of Lexer::singleEscape() | - | ||||||||||||
604 | QString Binding::escapedString(const QString &string) | - | ||||||||||||
605 | { | - | ||||||||||||
606 | QString tmp = QLatin1String("\""); | - | ||||||||||||
607 | for (int i = 0; i < string.length(); ++i) {
| 0 | ||||||||||||
608 | const QChar &c = string.at(i); | - | ||||||||||||
609 | switch (c.unicode()) { | - | ||||||||||||
610 | case 0x08: never executed: case 0x08: | 0 | ||||||||||||
611 | tmp += QLatin1String("\\b"); | - | ||||||||||||
612 | break; never executed: break; | 0 | ||||||||||||
613 | case 0x09: never executed: case 0x09: | 0 | ||||||||||||
614 | tmp += QLatin1String("\\t"); | - | ||||||||||||
615 | break; never executed: break; | 0 | ||||||||||||
616 | case 0x0A: never executed: case 0x0A: | 0 | ||||||||||||
617 | tmp += QLatin1String("\\n"); | - | ||||||||||||
618 | break; never executed: break; | 0 | ||||||||||||
619 | case 0x0B: never executed: case 0x0B: | 0 | ||||||||||||
620 | tmp += QLatin1String("\\v"); | - | ||||||||||||
621 | break; never executed: break; | 0 | ||||||||||||
622 | case 0x0C: never executed: case 0x0C: | 0 | ||||||||||||
623 | tmp += QLatin1String("\\f"); | - | ||||||||||||
624 | break; never executed: break; | 0 | ||||||||||||
625 | case 0x0D: never executed: case 0x0D: | 0 | ||||||||||||
626 | tmp += QLatin1String("\\r"); | - | ||||||||||||
627 | break; never executed: break; | 0 | ||||||||||||
628 | case 0x22: never executed: case 0x22: | 0 | ||||||||||||
629 | tmp += QLatin1String("\\\""); | - | ||||||||||||
630 | break; never executed: break; | 0 | ||||||||||||
631 | case 0x27: never executed: case 0x27: | 0 | ||||||||||||
632 | tmp += QLatin1String("\\\'"); | - | ||||||||||||
633 | break; never executed: break; | 0 | ||||||||||||
634 | case 0x5C: never executed: case 0x5C: | 0 | ||||||||||||
635 | tmp += QLatin1String("\\\\"); | - | ||||||||||||
636 | break; never executed: break; | 0 | ||||||||||||
637 | default: never executed: default: | 0 | ||||||||||||
638 | tmp += c; | - | ||||||||||||
639 | break; never executed: break; | 0 | ||||||||||||
640 | } | - | ||||||||||||
641 | } | - | ||||||||||||
642 | tmp += QLatin1Char('\"'); | - | ||||||||||||
643 | return tmp; never executed: return tmp; | 0 | ||||||||||||
644 | } | - | ||||||||||||
645 | - | |||||||||||||
646 | QString Binding::valueAsScriptString(const Unit *unit) const | - | ||||||||||||
647 | { | - | ||||||||||||
648 | if (type == Type_String)
| 0-4532 | ||||||||||||
649 | return escapedString(unit->stringAt(stringIndex)); never executed: return escapedString(unit->stringAt(stringIndex)); | 0 | ||||||||||||
650 | else | - | ||||||||||||
651 | return valueAsString(unit); executed 4532 times by 14 tests: return valueAsString(unit); Executed by:
| 4532 | ||||||||||||
652 | } | - | ||||||||||||
653 | - | |||||||||||||
654 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
655 | /*! | - | ||||||||||||
656 | Returns the property cache, if one alread exists. The cache is not referenced. | - | ||||||||||||
657 | */ | - | ||||||||||||
658 | QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::propertyCache() const | - | ||||||||||||
659 | { | - | ||||||||||||
660 | if (type.isValid()) | - | ||||||||||||
661 | return typePropertyCache; | - | ||||||||||||
662 | else | - | ||||||||||||
663 | return compilationUnit->rootPropertyCache(); | - | ||||||||||||
664 | } | - | ||||||||||||
665 | - | |||||||||||||
666 | /*! | - | ||||||||||||
667 | Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. | - | ||||||||||||
668 | */ | - | ||||||||||||
669 | QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQmlEngine *engine) | - | ||||||||||||
670 | { | - | ||||||||||||
671 | if (typePropertyCache) { | - | ||||||||||||
672 | return typePropertyCache; | - | ||||||||||||
673 | } else if (type.isValid()) { | - | ||||||||||||
674 | typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject()); | - | ||||||||||||
675 | return typePropertyCache; | - | ||||||||||||
676 | } else { | - | ||||||||||||
677 | return compilationUnit->rootPropertyCache(); | - | ||||||||||||
678 | } | - | ||||||||||||
679 | } | - | ||||||||||||
680 | - | |||||||||||||
681 | bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine) | - | ||||||||||||
682 | { | - | ||||||||||||
683 | if (type.isValid()) { | - | ||||||||||||
684 | bool ok = false; | - | ||||||||||||
685 | hash->addData(createPropertyCache(engine)->checksum(&ok)); | - | ||||||||||||
686 | return ok; | - | ||||||||||||
687 | } | - | ||||||||||||
688 | hash->addData(compilationUnit->data->md5Checksum, sizeof(compilationUnit->data->md5Checksum)); | - | ||||||||||||
689 | return true; | - | ||||||||||||
690 | } | - | ||||||||||||
691 | - | |||||||||||||
692 | template <typename T> | - | ||||||||||||
693 | bool qtTypeInherits(const QMetaObject *mo) { | - | ||||||||||||
694 | while (mo) { | - | ||||||||||||
695 | if (mo == &T::staticMetaObject) | - | ||||||||||||
696 | return true; | - | ||||||||||||
697 | mo = mo->superClass(); | - | ||||||||||||
698 | } | - | ||||||||||||
699 | return false; | - | ||||||||||||
700 | } | - | ||||||||||||
701 | - | |||||||||||||
702 | void ResolvedTypeReference::doDynamicTypeCheck() | - | ||||||||||||
703 | { | - | ||||||||||||
704 | const QMetaObject *mo = nullptr; | - | ||||||||||||
705 | if (typePropertyCache) | - | ||||||||||||
706 | mo = typePropertyCache->firstCppMetaObject(); | - | ||||||||||||
707 | else if (type.isValid()) | - | ||||||||||||
708 | mo = type.metaObject(); | - | ||||||||||||
709 | else if (compilationUnit) | - | ||||||||||||
710 | mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); | - | ||||||||||||
711 | isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo); | - | ||||||||||||
712 | } | - | ||||||||||||
713 | - | |||||||||||||
714 | bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const | - | ||||||||||||
715 | { | - | ||||||||||||
716 | for (auto it = constBegin(), end = constEnd(); it != end; ++it) { | - | ||||||||||||
717 | if (!it.value()->addToHash(hash, engine)) | - | ||||||||||||
718 | return false; | - | ||||||||||||
719 | } | - | ||||||||||||
720 | - | |||||||||||||
721 | return true; | - | ||||||||||||
722 | } | - | ||||||||||||
723 | - | |||||||||||||
724 | #endif | - | ||||||||||||
725 | - | |||||||||||||
726 | void CompilationUnit::destroy() | - | ||||||||||||
727 | { | - | ||||||||||||
728 | #if !defined(V4_BOOTSTRAP) | - | ||||||||||||
729 | if (qmlEngine) | - | ||||||||||||
730 | QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this); | - | ||||||||||||
731 | else | - | ||||||||||||
732 | #endif | - | ||||||||||||
733 | delete this; | - | ||||||||||||
734 | } executed 10 times by 1 test: end of block Executed by:
| 10 | ||||||||||||
735 | - | |||||||||||||
736 | - | |||||||||||||
737 | void Unit::generateChecksum() | - | ||||||||||||
738 | { | - | ||||||||||||
739 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
740 | QCryptographicHash hash(QCryptographicHash::Md5); | - | ||||||||||||
741 | - | |||||||||||||
742 | const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum); | - | ||||||||||||
743 | - | |||||||||||||
744 | const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset; | - | ||||||||||||
745 | hash.addData(dataPtr, unitSize - checksummableDataOffset); | - | ||||||||||||
746 | - | |||||||||||||
747 | QByteArray checksum = hash.result(); | - | ||||||||||||
748 | Q_ASSERT(checksum.size() == sizeof(md5Checksum)); | - | ||||||||||||
749 | memcpy(md5Checksum, checksum.constData(), sizeof(md5Checksum)); | - | ||||||||||||
750 | #else | - | ||||||||||||
751 | memset(md5Checksum, 0, sizeof(md5Checksum)); | - | ||||||||||||
752 | #endif | - | ||||||||||||
753 | } executed 2383537 times by 146 tests: end of block Executed by:
| 2383537 | ||||||||||||
754 | - | |||||||||||||
755 | bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const | - | ||||||||||||
756 | { | - | ||||||||||||
757 | #ifndef V4_BOOTSTRAP | - | ||||||||||||
758 | if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) { | - | ||||||||||||
759 | *errorString = QStringLiteral("Magic bytes in the header do not match"); | - | ||||||||||||
760 | return false; | - | ||||||||||||
761 | } | - | ||||||||||||
762 | - | |||||||||||||
763 | if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) { | - | ||||||||||||
764 | *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16); | - | ||||||||||||
765 | return false; | - | ||||||||||||
766 | } | - | ||||||||||||
767 | - | |||||||||||||
768 | if (qtVersion != quint32(QT_VERSION)) { | - | ||||||||||||
769 | *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16); | - | ||||||||||||
770 | return false; | - | ||||||||||||
771 | } | - | ||||||||||||
772 | - | |||||||||||||
773 | if (sourceTimeStamp) { | - | ||||||||||||
774 | // Files from the resource system do not have any time stamps, so fall back to the application | - | ||||||||||||
775 | // executable. | - | ||||||||||||
776 | if (!expectedSourceTimeStamp.isValid()) | - | ||||||||||||
777 | expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); | - | ||||||||||||
778 | - | |||||||||||||
779 | if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) { | - | ||||||||||||
780 | *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); | - | ||||||||||||
781 | return false; | - | ||||||||||||
782 | } | - | ||||||||||||
783 | } | - | ||||||||||||
784 | - | |||||||||||||
785 | #if defined(QML_COMPILE_HASH) | - | ||||||||||||
786 | if (qstrcmp(QML_COMPILE_HASH, libraryVersionHash) != 0) { | - | ||||||||||||
787 | *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match"); | - | ||||||||||||
788 | return false; | - | ||||||||||||
789 | } | - | ||||||||||||
790 | #else | - | ||||||||||||
791 | #error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" | - | ||||||||||||
792 | #endif | - | ||||||||||||
793 | - | |||||||||||||
794 | return true; | - | ||||||||||||
795 | #else | - | ||||||||||||
796 | Q_UNUSED(expectedSourceTimeStamp) | - | ||||||||||||
797 | Q_UNUSED(errorString) | - | ||||||||||||
798 | return false; never executed: return false; | 0 | ||||||||||||
799 | #endif | - | ||||||||||||
800 | } | - | ||||||||||||
801 | - | |||||||||||||
802 | } | - | ||||||||||||
803 | - | |||||||||||||
804 | } | - | ||||||||||||
805 | - | |||||||||||||
806 | QT_END_NAMESPACE | - | ||||||||||||
Source code | Switch to Preprocessed file |