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; |
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 | |
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 | |
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*/index: 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(akey: 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(idx: index); |
201 | } |
202 | |
203 | int importCount() const { return qmlData->nImports; } |
204 | const CompiledData::Import *importAt(int index) const |
205 | { |
206 | return qmlData->importAt(idx: 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(idx: 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: &resolveSet); |
255 | } |
256 | |
257 | QStringList exportedNames() const |
258 | { |
259 | QStringList names; |
260 | QVector<const ExecutableCompilationUnit*> exportNameSet; |
261 | getExportedNamesRecursively(names: &names, exportNameSet: &exportNameSet); |
262 | names.sort(); |
263 | auto last = std::unique(first: names.begin(), last: names.end()); |
264 | names.erase(afirst: last, alast: 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 (const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, |
291 | QString *errorString); |
292 | |
293 | protected: |
294 | quint32 totalStringCount() const |
295 | { return data->stringTableSize; } |
296 | |
297 | private: |
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 | |
326 | struct ResolvedTypeReference |
327 | { |
328 | public: |
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; |
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 | |
397 | IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex) |
398 | { |
399 | auto it = namedObjectsPerComponentCache.find(akey: 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 | |