1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QV4EXECUTABLECOMPILATIONUNIT_P_H |
5 | #define QV4EXECUTABLECOMPILATIONUNIT_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <private/qv4compileddata_p.h> |
19 | #include <private/qv4identifierhash_p.h> |
20 | #include <private/qqmlrefcount_p.h> |
21 | #include <private/qintrusivelist_p.h> |
22 | #include <private/qqmlpropertycachevector_p.h> |
23 | #include <private/qqmltype_p.h> |
24 | #include <private/qqmlnullablevalue_p.h> |
25 | #include <private/qqmlmetatype_p.h> |
26 | |
27 | #include <memory> |
28 | |
29 | QT_BEGIN_NAMESPACE |
30 | |
31 | class QQmlScriptData; |
32 | class QQmlEnginePrivate; |
33 | |
34 | struct InlineComponentData { |
35 | |
36 | InlineComponentData() = default; |
37 | InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount) |
38 | : typeIds(typeIds) |
39 | , objectIndex(objectIndex) |
40 | , nameIndex(nameIndex) |
41 | , totalObjectCount(totalObjectCount) |
42 | , totalBindingCount(totalBindingCount) |
43 | , totalParserStatusCount(totalParserStatusCount) {} |
44 | |
45 | CompositeMetaTypeIds typeIds; |
46 | int objectIndex = -1; |
47 | int nameIndex = -1; |
48 | int totalObjectCount = 0; |
49 | int totalBindingCount = 0; |
50 | int totalParserStatusCount = 0; |
51 | }; |
52 | |
53 | namespace QV4 { |
54 | |
55 | // index is per-object binding index |
56 | typedef QVector<const QQmlPropertyData *> BindingPropertyData; |
57 | |
58 | class CompilationUnitMapper; |
59 | class ResolvedTypeReference; |
60 | // map from name index |
61 | struct ResolvedTypeReferenceMap: public QHash<int, ResolvedTypeReference*> |
62 | { |
63 | bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const; |
64 | }; |
65 | |
66 | class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final |
67 | : public CompiledData::CompilationUnit, |
68 | public QQmlRefCounted<ExecutableCompilationUnit> |
69 | { |
70 | Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit) |
71 | public: |
72 | friend class QQmlRefPointer<ExecutableCompilationUnit>; |
73 | |
74 | static QQmlRefPointer<ExecutableCompilationUnit> create( |
75 | CompiledData::CompilationUnit &&compilationUnit) |
76 | { |
77 | return QQmlRefPointer<ExecutableCompilationUnit>( |
78 | new ExecutableCompilationUnit(std::move(compilationUnit)), |
79 | QQmlRefPointer<ExecutableCompilationUnit>::Adopt); |
80 | } |
81 | |
82 | static QQmlRefPointer<ExecutableCompilationUnit> create() |
83 | { |
84 | return QQmlRefPointer<ExecutableCompilationUnit>( |
85 | new ExecutableCompilationUnit, |
86 | QQmlRefPointer<ExecutableCompilationUnit>::Adopt); |
87 | } |
88 | |
89 | QIntrusiveListNode nextCompilationUnit; |
90 | ExecutionEngine *engine = nullptr; |
91 | |
92 | // url() and fileName() shall be used to load the actual QML/JS code or to show errors or |
93 | // warnings about that code. They include any potential URL interceptions and thus represent the |
94 | // "physical" location of the code. |
95 | // |
96 | // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code |
97 | // They are _not_ intercepted and thus represent the "logical" name for the code. |
98 | |
99 | QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; } |
100 | QUrl finalUrl() const |
101 | { |
102 | if (m_finalUrl.isNull) |
103 | m_finalUrl = QUrl(finalUrlString()); |
104 | return m_finalUrl; |
105 | } |
106 | |
107 | QV4::Lookup *runtimeLookups = nullptr; |
108 | QVector<QV4::Function *> runtimeFunctions; |
109 | QVector<QV4::Heap::InternalClass *> runtimeBlocks; |
110 | mutable QVector<QV4::Heap::Object *> templateObjects; |
111 | mutable QQmlNullableValue<QUrl> m_url; |
112 | mutable QQmlNullableValue<QUrl> m_finalUrl; |
113 | |
114 | // QML specific fields |
115 | QQmlPropertyCacheVector propertyCaches; |
116 | QQmlPropertyCache::ConstPtr rootPropertyCache() const { return propertyCaches.at(/*root object*/index: 0); } |
117 | |
118 | QQmlRefPointer<QQmlTypeNameCache> typeNameCache; |
119 | |
120 | // index is object index. This allows fast access to the |
121 | // property data when initializing bindings, avoiding expensive |
122 | // lookups by string (property name). |
123 | QVector<BindingPropertyData> bindingPropertyDataPerObject; |
124 | |
125 | // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects |
126 | // this is initialized on-demand by QQmlContextData |
127 | QHash<int, IdentifierHash> namedObjectsPerComponentCache; |
128 | inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex); |
129 | |
130 | void finalizeCompositeType(CompositeMetaTypeIds typeIdsForComponent); |
131 | |
132 | int m_totalBindingsCount = 0; // Number of bindings used in this type |
133 | int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses |
134 | int m_totalObjectCount = 0; // Number of objects explicitly instantiated |
135 | std::unique_ptr<QString> icRootName; |
136 | |
137 | int totalBindingsCount() const; |
138 | int totalParserStatusCount() const; |
139 | int totalObjectCount() const; |
140 | |
141 | QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts; |
142 | ResolvedTypeReferenceMap resolvedTypes; |
143 | ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(key: id); } |
144 | |
145 | bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; |
146 | |
147 | CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const; |
148 | |
149 | CompositeMetaTypeIds typeIds; |
150 | bool isRegistered = false; |
151 | |
152 | QHash<QString, InlineComponentData> inlineComponentData; |
153 | |
154 | int inlineComponentId(const QString &inlineComponentName) const |
155 | { |
156 | for (int i = 0; i < objectCount(); ++i) { |
157 | auto *object = objectAt(index: i); |
158 | for (auto it = object->inlineComponentsBegin(), end = object->inlineComponentsEnd(); |
159 | it != end; ++it) { |
160 | if (stringAt(index: it->nameIndex) == inlineComponentName) |
161 | return it->objectIndex; |
162 | } |
163 | } |
164 | return -1; |
165 | } |
166 | |
167 | std::unique_ptr<CompilationUnitMapper> backingFile; |
168 | |
169 | // --- interface for QQmlPropertyCacheCreator |
170 | using CompiledObject = const CompiledData::Object; |
171 | using CompiledFunction = const CompiledData::Function; |
172 | using CompiledBinding = const CompiledData::Binding; |
173 | enum class ListPropertyAssignBehavior { Append, Replace, ReplaceIfNotDefault }; |
174 | |
175 | // Empty dummy. We don't need to do this when loading from cache. |
176 | class IdToObjectMap |
177 | { |
178 | public: |
179 | void insert(int, int) {} |
180 | void clear() {} |
181 | |
182 | // We have already checked uniqueness of IDs when creating the CU |
183 | bool contains(int) { return false; } |
184 | }; |
185 | |
186 | ListPropertyAssignBehavior listPropertyAssignBehavior() const |
187 | { |
188 | if (data->flags & CompiledData::Unit::ListPropertyAssignReplace) |
189 | return ListPropertyAssignBehavior::Replace; |
190 | if (data->flags & CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault) |
191 | return ListPropertyAssignBehavior::ReplaceIfNotDefault; |
192 | return ListPropertyAssignBehavior::Append; |
193 | } |
194 | |
195 | bool enforcesFunctionSignature() const |
196 | { |
197 | return data->flags & CompiledData::Unit::FunctionSignaturesEnforced; |
198 | } |
199 | |
200 | bool nativeMethodsAcceptThisObjects() const |
201 | { |
202 | return data->flags & CompiledData::Unit::NativeMethodsAcceptThisObject; |
203 | } |
204 | |
205 | bool valueTypesAreCopied() const |
206 | { |
207 | return data->flags & CompiledData::Unit::ValueTypesCopied; |
208 | } |
209 | |
210 | bool valueTypesAreAddressable() const |
211 | { |
212 | return data->flags & CompiledData::Unit::ValueTypesAddressable; |
213 | } |
214 | |
215 | int objectCount() const { return qmlData->nObjects; } |
216 | const CompiledObject *objectAt(int index) const |
217 | { |
218 | return qmlData->objectAt(idx: index); |
219 | } |
220 | |
221 | int importCount() const { return qmlData->nImports; } |
222 | const CompiledData::Import *importAt(int index) const |
223 | { |
224 | return qmlData->importAt(idx: index); |
225 | } |
226 | |
227 | Heap::Object *templateObjectAt(int index) const; |
228 | |
229 | struct FunctionIterator |
230 | { |
231 | FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index) |
232 | : unit(unit), object(object), index(index) {} |
233 | const CompiledData::Unit *unit; |
234 | const CompiledObject *object; |
235 | int index; |
236 | |
237 | const CompiledFunction *operator->() const |
238 | { |
239 | return unit->functionAt(idx: object->functionOffsetTable()[index]); |
240 | } |
241 | |
242 | void operator++() { ++index; } |
243 | bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; } |
244 | bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; } |
245 | }; |
246 | |
247 | FunctionIterator objectFunctionsBegin(const CompiledObject *object) const |
248 | { |
249 | return FunctionIterator(data, object, 0); |
250 | } |
251 | |
252 | FunctionIterator objectFunctionsEnd(const CompiledObject *object) const |
253 | { |
254 | return FunctionIterator(data, object, object->nFunctions); |
255 | } |
256 | |
257 | bool isESModule() const |
258 | { |
259 | return data->flags & CompiledData::Unit::IsESModule; |
260 | } |
261 | |
262 | bool isSharedLibrary() const |
263 | { |
264 | return data->flags & CompiledData::Unit::IsSharedLibrary; |
265 | } |
266 | |
267 | QStringList moduleRequests() const; |
268 | Heap::Module *instantiate(ExecutionEngine *engine); |
269 | const Value *resolveExport(QV4::String *exportName) |
270 | { |
271 | QVector<ResolveSetEntry> resolveSet; |
272 | return resolveExportRecursively(exportName, resolveSet: &resolveSet); |
273 | } |
274 | |
275 | QStringList exportedNames() const |
276 | { |
277 | QStringList names; |
278 | QVector<const ExecutableCompilationUnit*> exportNameSet; |
279 | getExportedNamesRecursively(names: &names, exportNameSet: &exportNameSet); |
280 | names.sort(); |
281 | auto last = std::unique(first: names.begin(), last: names.end()); |
282 | names.erase(abegin: last, aend: names.end()); |
283 | return names; |
284 | } |
285 | |
286 | void evaluate(); |
287 | void evaluateModuleRequests(); |
288 | |
289 | QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); |
290 | void unlink(); |
291 | |
292 | void markObjects(MarkStack *markStack); |
293 | |
294 | bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString); |
295 | |
296 | static QString localCacheFilePath(const QUrl &url); |
297 | bool saveToDisk(const QUrl &unitUrl, QString *errorString); |
298 | |
299 | QString bindingValueAsString(const CompiledData::Binding *binding) const; |
300 | |
301 | struct TranslationDataIndex |
302 | { |
303 | uint index; |
304 | bool byId; |
305 | }; |
306 | |
307 | QString translateFrom(TranslationDataIndex index) const; |
308 | |
309 | static bool (const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, |
310 | QString *errorString); |
311 | protected: |
312 | quint32 totalStringCount() const |
313 | { return data->stringTableSize; } |
314 | |
315 | private: |
316 | struct ResolveSetEntry |
317 | { |
318 | ResolveSetEntry() {} |
319 | ResolveSetEntry(ExecutableCompilationUnit *module, QV4::String *exportName) |
320 | : module(module), exportName(exportName) {} |
321 | ExecutableCompilationUnit *module = nullptr; |
322 | QV4::String *exportName = nullptr; |
323 | }; |
324 | |
325 | ExecutableCompilationUnit(); |
326 | ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit); |
327 | ~ExecutableCompilationUnit(); |
328 | |
329 | const Value *resolveExportRecursively(QV4::String *exportName, |
330 | QVector<ResolveSetEntry> *resolveSet); |
331 | |
332 | QUrl urlAt(int index) const { return QUrl(stringAt(index)); } |
333 | |
334 | Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex); |
335 | const CompiledData::ExportEntry *lookupNameInExportTable( |
336 | const CompiledData::ExportEntry *firstExportEntry, int tableSize, |
337 | QV4::String *name) const; |
338 | |
339 | void getExportedNamesRecursively( |
340 | QStringList *names, QVector<const ExecutableCompilationUnit *> *exportNameSet, |
341 | bool includeDefaultExport = true) const; |
342 | }; |
343 | |
344 | IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex) |
345 | { |
346 | auto it = namedObjectsPerComponentCache.find(key: componentObjectIndex); |
347 | if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end())) |
348 | return createNamedObjectsPerComponent(componentObjectIndex); |
349 | Q_ASSERT(!it->isEmpty()); |
350 | return *it; |
351 | } |
352 | |
353 | } // namespace QV4 |
354 | |
355 | QT_END_NAMESPACE |
356 | |
357 | #endif // QV4EXECUTABLECOMPILATIONUNIT_P_H |
358 | |