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
63QT_BEGIN_NAMESPACE
64
65class QQmlScriptData;
66class QQmlEnginePrivate;
67
68struct InlineComponentData {
69
70 InlineComponentData() = default;
71 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
87namespace QV4 {
88
89// index is per-object binding index
90typedef QVector<QQmlPropertyData*> BindingPropertyData;
91
92class CompilationUnitMapper;
93struct 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.
97struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
98{
99 bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
100};
101
102class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit,
103 public QQmlRefCount
104{
105 Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit)
106public:
107 friend class QQmlRefPointer<ExecutableCompilationUnit>;
108
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
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
135 QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
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;
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;
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
197 int objectCount() const { return qmlData->nObjects; }
198 const CompiledObject *objectAt(int index) const
199 {
200 return qmlData->objectAt(index);
201 }
202
203 int importCount() const { return qmlData->nImports; }
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 {
213 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
229 FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
230 {
231 return FunctionIterator(data, object, 0);
232 }
233
234 FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
235 {
236 return FunctionIterator(data, object, object->nFunctions);
237 }
238
239 bool isESModule() const
240 {
241 return data->flags & CompiledData::Unit::IsESModule;
242 }
243
244 bool isSharedLibrary() const
245 {
246 return data->flags & CompiledData::Unit::IsSharedLibrary;
247 }
248
249 QStringList moduleRequests() const;
250 Heap::Module *instantiate(ExecutionEngine *engine);
251 const Value *resolveExport(QV4::String *exportName)
252 {
253 QVector<ResolveSetEntry> resolveSet;
254 return resolveExportRecursively(exportName, &resolveSet);
255 }
256
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;
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
293protected:
294 quint32 totalStringCount() const
295 { return data->stringTableSize; }
296
297private:
298 struct ResolveSetEntry
299 {
300 ResolveSetEntry() {}
301 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
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
326struct ResolvedTypeReference
327{
328public:
329 ResolvedTypeReference()
330 : m_compilationUnit(nullptr)
331 , m_stronglyReferencesCompilationUnit(true)
332 , majorVersion(0)
333 , minorVersion(0)
334 , isFullyDynamicType(false)
335 {}
336
337 ~ResolvedTypeReference()
338 {
339 if (m_stronglyReferencesCompilationUnit && m_compilationUnit)
340 m_compilationUnit->release();
341 }
342
343 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() { return m_compilationUnit; }
344 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
357 bool referencesCompilationUnit() const { return m_stronglyReferencesCompilationUnit; }
358 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;
383private:
384 Q_DISABLE_COPY_MOVE(ResolvedTypeReference)
385
386 QV4::ExecutableCompilationUnit *m_compilationUnit;
387 bool m_stronglyReferencesCompilationUnit;
388
389public:
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
397IdentifierHash 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
407QT_END_NAMESPACE
408
409#endif // QV4EXECUTABLECOMPILATIONUNIT_P_H
410

source code of qtdeclarative/src/qml/jsruntime/qv4executablecompilationunit_p.h