1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the tools applications 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 #ifndef QV4EXECUTABLECOMPILATIONUNIT_P_H
41 #define QV4EXECUTABLECOMPILATIONUNIT_P_H
42
43 //
44 // W A R N I N G
45 // -------------
46 //
47 // This file is not part of the Qt API. It exists purely as an
48 // implementation detail. This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53
54 #include <private/qv4compileddata_p.h>
55 #include <private/qv4identifier_p.h>
56 #include <private/qqmlrefcount_p.h>
57 #include <private/qintrusivelist_p.h>
58 #include <private/qqmlpropertycachevector_p.h>
59 #include <private/qqmltype_p.h>
60 #include <private/qqmlnullablevalue_p.h>
61 #include <private/qqmlmetatype_p.h>
62
63 QT_BEGIN_NAMESPACE
64
65 class QQmlScriptData;
66 class QQmlEnginePrivate;
67
68 struct InlineComponentData {
69
70 InlineComponentData() = default;
InlineComponentDataInlineComponentData71 InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount)
72 : typeIds(typeIds)
73 , objectIndex(objectIndex)
74 , nameIndex(nameIndex)
75 , totalObjectCount(totalObjectCount)
76 , totalBindingCount(totalBindingCount)
77 , totalParserStatusCount(totalParserStatusCount) {}
78
79 CompositeMetaTypeIds typeIds;
80 int objectIndex = -1;
81 int nameIndex = -1;
82 int totalObjectCount = 0;
83 int totalBindingCount = 0;
84 int totalParserStatusCount = 0;
85 };
86
87 namespace QV4 {
88
89 // index is per-object binding index
90 typedef QVector<QQmlPropertyData*> BindingPropertyData;
91
92 class CompilationUnitMapper;
93 struct ResolvedTypeReference;
94 // map from name index
95 // While this could be a hash, a map is chosen here to provide a stable
96 // order, which is used to calculating a check-sum on dependent meta-objects.
97 struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
98 {
99 bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
100 };
101
102 class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit,
103 public QQmlRefCount
104 {
105 Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit)
106 public:
107 friend class QQmlRefPointer<ExecutableCompilationUnit>;
108
create(CompiledData::CompilationUnit && compilationUnit)109 static QQmlRefPointer<ExecutableCompilationUnit> create(
110 CompiledData::CompilationUnit &&compilationUnit)
111 {
112 return QQmlRefPointer<ExecutableCompilationUnit>(
113 new ExecutableCompilationUnit(std::move(compilationUnit)),
114 QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
115 }
116
create()117 static QQmlRefPointer<ExecutableCompilationUnit> create()
118 {
119 return QQmlRefPointer<ExecutableCompilationUnit>(
120 new ExecutableCompilationUnit,
121 QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
122 }
123
124 QIntrusiveListNode nextCompilationUnit;
125 ExecutionEngine *engine = nullptr;
126 QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
127
128 // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
129 // warnings about that code. They include any potential URL interceptions and thus represent the
130 // "physical" location of the code.
131 //
132 // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
133 // They are _not_ intercepted and thus represent the "logical" name for the code.
134
url()135 QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
finalUrl()136 QUrl finalUrl() const
137 {
138 if (m_finalUrl.isNull)
139 m_finalUrl = QUrl(finalUrlString());
140 return m_finalUrl;
141 }
142
143 QV4::Lookup *runtimeLookups = nullptr;
144 QVector<QV4::Function *> runtimeFunctions;
145 QVector<QV4::Heap::InternalClass *> runtimeBlocks;
146 mutable QVector<QV4::Heap::Object *> templateObjects;
147 mutable QQmlNullableValue<QUrl> m_url;
148 mutable QQmlNullableValue<QUrl> m_finalUrl;
149
150 // QML specific fields
151 QQmlPropertyCacheVector propertyCaches;
rootPropertyCache()152 QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
153
154 QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
155
156 // index is object index. This allows fast access to the
157 // property data when initializing bindings, avoiding expensive
158 // lookups by string (property name).
159 QVector<BindingPropertyData> bindingPropertyDataPerObject;
160
161 // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
162 // this is initialized on-demand by QQmlContextData
163 QHash<int, IdentifierHash> namedObjectsPerComponentCache;
164 inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
165
166 void finalizeCompositeType(QQmlEnginePrivate *qmlEngine, CompositeMetaTypeIds typeIdsForComponent);
167
168 int m_totalBindingsCount = 0; // Number of bindings used in this type
169 int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
170 int m_totalObjectCount = 0; // Number of objects explicitly instantiated
171 int icRoot = -1;
172
173 int totalBindingsCount() const;
174 int totalParserStatusCount() const;
175 int totalObjectCount() const;
176
177 QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
178 ResolvedTypeReferenceMap resolvedTypes;
resolvedType(int id)179 ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
180
181 bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
182
183 CompositeMetaTypeIds typeIdsForComponent(int objectid = 0) const;
184
185 int metaTypeId = -1;
186 int listMetaTypeId = -1;
187 bool isRegisteredWithEngine = false;
188
189 QHash<int, InlineComponentData> inlineComponentData;
190
191 QScopedPointer<CompilationUnitMapper> backingFile;
192
193 // --- interface for QQmlPropertyCacheCreator
194 using CompiledObject = CompiledData::Object;
195 using CompiledFunction = CompiledData::Function;
196
objectCount()197 int objectCount() const { return qmlData->nObjects; }
objectAt(int index)198 const CompiledObject *objectAt(int index) const
199 {
200 return qmlData->objectAt(index);
201 }
202
importCount()203 int importCount() const { return qmlData->nImports; }
importAt(int index)204 const CompiledData::Import *importAt(int index) const
205 {
206 return qmlData->importAt(index);
207 }
208
209 Heap::Object *templateObjectAt(int index) const;
210
211 struct FunctionIterator
212 {
FunctionIteratorFunctionIterator213 FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
214 : unit(unit), object(object), index(index) {}
215 const CompiledData::Unit *unit;
216 const CompiledObject *object;
217 int index;
218
219 const CompiledFunction *operator->() const
220 {
221 return unit->functionAt(object->functionOffsetTable()[index]);
222 }
223
224 void operator++() { ++index; }
225 bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
226 bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
227 };
228
objectFunctionsBegin(const CompiledObject * object)229 FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
230 {
231 return FunctionIterator(data, object, 0);
232 }
233
objectFunctionsEnd(const CompiledObject * object)234 FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
235 {
236 return FunctionIterator(data, object, object->nFunctions);
237 }
238
isESModule()239 bool isESModule() const
240 {
241 return data->flags & CompiledData::Unit::IsESModule;
242 }
243
isSharedLibrary()244 bool isSharedLibrary() const
245 {
246 return data->flags & CompiledData::Unit::IsSharedLibrary;
247 }
248
249 QStringList moduleRequests() const;
250 Heap::Module *instantiate(ExecutionEngine *engine);
resolveExport(QV4::String * exportName)251 const Value *resolveExport(QV4::String *exportName)
252 {
253 QVector<ResolveSetEntry> resolveSet;
254 return resolveExportRecursively(exportName, &resolveSet);
255 }
256
exportedNames()257 QStringList exportedNames() const
258 {
259 QStringList names;
260 QVector<const ExecutableCompilationUnit*> exportNameSet;
261 getExportedNamesRecursively(&names, &exportNameSet);
262 names.sort();
263 auto last = std::unique(names.begin(), names.end());
264 names.erase(last, names.end());
265 return names;
266 }
267
268 void evaluate();
269 void evaluateModuleRequests();
270
271 QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
272 void unlink();
273
274 void markObjects(MarkStack *markStack);
275
276 bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
277
278 static QString localCacheFilePath(const QUrl &url);
279 bool saveToDisk(const QUrl &unitUrl, QString *errorString);
280
281 QString bindingValueAsString(const CompiledData::Binding *binding) const;
282 QString bindingValueAsScriptString(const CompiledData::Binding *binding) const;
bindingValueAsNumber(const CompiledData::Binding * binding)283 double bindingValueAsNumber(const CompiledData::Binding *binding) const
284 {
285 if (binding->type != CompiledData::Binding::Type_Number)
286 return 0.0;
287 return constants[binding->value.constantValueIndex].doubleValue();
288 }
289
290 static bool verifyHeader(const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp,
291 QString *errorString);
292
293 protected:
totalStringCount()294 quint32 totalStringCount() const
295 { return data->stringTableSize; }
296
297 private:
298 struct ResolveSetEntry
299 {
ResolveSetEntryResolveSetEntry300 ResolveSetEntry() {}
ResolveSetEntryResolveSetEntry301 ResolveSetEntry(ExecutableCompilationUnit *module, QV4::String *exportName)
302 : module(module), exportName(exportName) {}
303 ExecutableCompilationUnit *module = nullptr;
304 QV4::String *exportName = nullptr;
305 };
306
307 ExecutableCompilationUnit();
308 ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit);
309 ~ExecutableCompilationUnit();
310
311 const Value *resolveExportRecursively(QV4::String *exportName,
312 QVector<ResolveSetEntry> *resolveSet);
313
urlAt(int index)314 QUrl urlAt(int index) const { return QUrl(stringAt(index)); }
315
316 Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex);
317 const CompiledData::ExportEntry *lookupNameInExportTable(
318 const CompiledData::ExportEntry *firstExportEntry, int tableSize,
319 QV4::String *name) const;
320
321 void getExportedNamesRecursively(
322 QStringList *names, QVector<const ExecutableCompilationUnit *> *exportNameSet,
323 bool includeDefaultExport = true) const;
324 };
325
326 struct ResolvedTypeReference
327 {
328 public:
ResolvedTypeReferenceResolvedTypeReference329 ResolvedTypeReference()
330 : m_compilationUnit(nullptr)
331 , m_stronglyReferencesCompilationUnit(true)
332 , majorVersion(0)
333 , minorVersion(0)
334 , isFullyDynamicType(false)
335 {}
336
~ResolvedTypeReferenceResolvedTypeReference337 ~ResolvedTypeReference()
338 {
339 if (m_stronglyReferencesCompilationUnit && m_compilationUnit)
340 m_compilationUnit->release();
341 }
342
compilationUnitResolvedTypeReference343 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() { return m_compilationUnit; }
setCompilationUnitResolvedTypeReference344 void setCompilationUnit(QQmlRefPointer<QV4::ExecutableCompilationUnit> unit)
345 {
346 if (m_compilationUnit == unit.data())
347 return;
348 if (m_stronglyReferencesCompilationUnit) {
349 if (m_compilationUnit)
350 m_compilationUnit->release();
351 m_compilationUnit = unit.take();
352 } else {
353 m_compilationUnit = unit.data();
354 }
355 }
356
referencesCompilationUnitResolvedTypeReference357 bool referencesCompilationUnit() const { return m_stronglyReferencesCompilationUnit; }
setReferencesCompilationUnitResolvedTypeReference358 void setReferencesCompilationUnit(bool doReference)
359 {
360 if (doReference == m_stronglyReferencesCompilationUnit)
361 return;
362 m_stronglyReferencesCompilationUnit = doReference;
363 if (!m_compilationUnit)
364 return;
365 if (doReference) {
366 m_compilationUnit->addref();
367 } else if (m_compilationUnit->count() == 1) {
368 m_compilationUnit->release();
369 m_compilationUnit = nullptr;
370 } else {
371 m_compilationUnit->release();
372 }
373 }
374
375 QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
376 QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
377 bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
378
379 void doDynamicTypeCheck();
380
381 QQmlType type;
382 QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
383 private:
384 Q_DISABLE_COPY_MOVE(ResolvedTypeReference)
385
386 QV4::ExecutableCompilationUnit *m_compilationUnit;
387 bool m_stronglyReferencesCompilationUnit;
388
389 public:
390 int majorVersion;
391 int minorVersion;
392 // Types such as QQmlPropertyMap can add properties dynamically at run-time and
393 // therefore cannot have a property cache installed when instantiated.
394 bool isFullyDynamicType;
395 };
396
namedObjectsPerComponent(int componentObjectIndex)397 IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
398 {
399 auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
400 if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
401 return createNamedObjectsPerComponent(componentObjectIndex);
402 return *it;
403 }
404
405 } // namespace QV4
406
407 QT_END_NAMESPACE
408
409 #endif // QV4EXECUTABLECOMPILATIONUNIT_P_H
410