1 | // Copyright (C) 2016 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 | #ifndef QV4COMPILEDDATA_P_H |
4 | #define QV4COMPILEDDATA_P_H |
5 | |
6 | // |
7 | // W A R N I N G |
8 | // ------------- |
9 | // |
10 | // This file is not part of the Qt API. It exists purely as an |
11 | // implementation detail. This header file may change from version to |
12 | // version without notice, or even be removed. |
13 | // |
14 | // We mean it. |
15 | // |
16 | |
17 | #include <functional> |
18 | |
19 | #include <QtCore/qcryptographichash.h> |
20 | #include <QtCore/qhash.h> |
21 | #include <QtCore/qhashfunctions.h> |
22 | #include <QtCore/qlocale.h> |
23 | #include <QtCore/qscopeguard.h> |
24 | #include <QtCore/qstring.h> |
25 | #include <QtCore/qstringlist.h> |
26 | #include <QtCore/qurl.h> |
27 | #include <QtCore/qvector.h> |
28 | #include <QtCore/qversionnumber.h> |
29 | |
30 | #if QT_CONFIG(temporaryfile) |
31 | #include <QtCore/qsavefile.h> |
32 | #endif |
33 | |
34 | #include <private/qendian_p.h> |
35 | #include <private/qqmlnullablevalue_p.h> |
36 | #include <private/qqmlpropertycachevector_p.h> |
37 | #include <private/qqmlrefcount_p.h> |
38 | #include <private/qqmltype_p.h> |
39 | #include <private/qv4compilationunitmapper_p.h> |
40 | #include <private/qv4staticvalue_p.h> |
41 | |
42 | #include <functional> |
43 | #include <limits.h> |
44 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | // Bump this whenever the compiler data structures change in an incompatible way. |
48 | // |
49 | // IMPORTANT: |
50 | // |
51 | // Also change the comment behind the number to describe the latest change. This has the added |
52 | // benefit that if another patch changes the version too, it will result in a merge conflict, and |
53 | // not get removed silently. |
54 | #define QV4_DATA_STRUCTURE_VERSION 0x42 // Change metatype computation of AOT-compiled functions |
55 | |
56 | class QIODevice; |
57 | class QQmlTypeNameCache; |
58 | class QQmlType; |
59 | class QQmlEngine; |
60 | class QQmlPropertyData; |
61 | class QQmlScriptData; |
62 | |
63 | namespace QQmlPrivate { |
64 | struct AOTCompiledFunction; |
65 | } |
66 | |
67 | namespace QmlIR { |
68 | struct Document; |
69 | } |
70 | |
71 | namespace QV4 { |
72 | namespace Heap { |
73 | struct Module; |
74 | struct String; |
75 | struct InternalClass; |
76 | }; |
77 | |
78 | struct Function; |
79 | class EvalISelFactory; |
80 | class ResolvedTypeReference; |
81 | |
82 | namespace CompiledData { |
83 | |
84 | // index is per-object binding index |
85 | using BindingPropertyData = QVector<const QQmlPropertyData *>; |
86 | |
87 | // map from name index |
88 | struct ResolvedTypeReferenceMap: public QHash<int, ResolvedTypeReference*> |
89 | { |
90 | bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const; |
91 | }; |
92 | |
93 | struct String; |
94 | struct Function; |
95 | struct Lookup; |
96 | struct RegExp; |
97 | struct Unit; |
98 | |
99 | template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const> |
100 | struct TableIterator |
101 | { |
102 | TableIterator(const Container *container, int index) : container(container), index(index) {} |
103 | const Container *container; |
104 | int index; |
105 | |
106 | const ItemType *operator->() { return (container->*IndexedGetter)(index); } |
107 | ItemType operator*() {return *operator->();} |
108 | void operator++() { ++index; } |
109 | bool operator==(const TableIterator &rhs) const { return index == rhs.index; } |
110 | bool operator!=(const TableIterator &rhs) const { return index != rhs.index; } |
111 | }; |
112 | |
113 | struct Location |
114 | { |
115 | Location() : m_data(QSpecialIntegerBitfieldZero) {} |
116 | Location(quint32 l, quint32 c) : Location() |
117 | { |
118 | m_data.set<LineField>(l); |
119 | m_data.set<ColumnField>(c); |
120 | Q_ASSERT(m_data.get<LineField>() == l); |
121 | Q_ASSERT(m_data.get<ColumnField>() == c); |
122 | } |
123 | |
124 | inline bool operator<(const Location &other) const { |
125 | return m_data.get<LineField>() < other.m_data.get<LineField>() |
126 | || (m_data.get<LineField>() == other.m_data.get<LineField>() |
127 | && m_data.get<ColumnField>() < other.m_data.get<ColumnField>()); |
128 | } |
129 | |
130 | friend size_t qHash(const Location &location, size_t seed = 0) |
131 | { |
132 | return QT_PREPEND_NAMESPACE(qHash)(key: location.m_data.data(), seed); |
133 | } |
134 | |
135 | friend bool operator==(const Location &a, const Location &b) |
136 | { |
137 | return a.m_data.data()== b.m_data.data(); |
138 | } |
139 | |
140 | void set(quint32 line, quint32 column) |
141 | { |
142 | m_data.set<LineField>(line); |
143 | m_data.set<ColumnField>(column); |
144 | } |
145 | |
146 | quint32 line() const { return m_data.get<LineField>(); } |
147 | quint32 column() const { return m_data.get<ColumnField>(); } |
148 | |
149 | private: |
150 | using LineField = quint32_le_bitfield_member<0, 20>; |
151 | using ColumnField = quint32_le_bitfield_member<20, 12>; |
152 | |
153 | quint32_le_bitfield_union<LineField, ColumnField> m_data; |
154 | }; |
155 | static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
156 | |
157 | struct RegExp |
158 | { |
159 | enum Flags : unsigned int { |
160 | RegExp_NoFlags = 0x0, |
161 | RegExp_Global = 0x01, |
162 | RegExp_IgnoreCase = 0x02, |
163 | RegExp_Multiline = 0x04, |
164 | RegExp_Sticky = 0x08, |
165 | RegExp_Unicode = 0x10, |
166 | }; |
167 | |
168 | RegExp() : m_data(QSpecialIntegerBitfieldZero) {} |
169 | RegExp(quint32 flags, quint32 stringIndex) : RegExp() |
170 | { |
171 | m_data.set<FlagsField>(flags); |
172 | m_data.set<StringIndexField>(stringIndex); |
173 | } |
174 | |
175 | quint32 flags() const { return m_data.get<FlagsField>(); } |
176 | quint32 stringIndex() const { return m_data.get<StringIndexField>(); } |
177 | |
178 | private: |
179 | using FlagsField = quint32_le_bitfield_member<0, 5>; |
180 | using StringIndexField = quint32_le_bitfield_member<5, 27>; |
181 | quint32_le_bitfield_union<FlagsField, StringIndexField> m_data; |
182 | }; |
183 | static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
184 | |
185 | struct Lookup |
186 | { |
187 | enum Type : unsigned int { |
188 | Type_Getter = 0, |
189 | Type_Setter = 1, |
190 | Type_GlobalGetter = 2, |
191 | Type_QmlContextPropertyGetter = 3 |
192 | }; |
193 | |
194 | enum Mode : unsigned int { |
195 | Mode_ForStorage = 0, |
196 | Mode_ForCall = 1 |
197 | }; |
198 | |
199 | quint32 type() const { return m_data.get<TypeField>(); } |
200 | quint32 nameIndex() const { return m_data.get<NameIndexField>(); } |
201 | quint32 mode() const { return m_data.get<ModeField>(); } |
202 | |
203 | Lookup() : m_data(QSpecialIntegerBitfieldZero) {} |
204 | Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup() |
205 | { |
206 | m_data.set<TypeField>(type); |
207 | m_data.set<ModeField>(mode); |
208 | m_data.set<NameIndexField>(nameIndex); |
209 | } |
210 | |
211 | private: |
212 | using TypeField = quint32_le_bitfield_member<0, 2>; |
213 | using ModeField = quint32_le_bitfield_member<2, 1>; |
214 | // 1 bit left |
215 | using NameIndexField = quint32_le_bitfield_member<4, 28>; |
216 | quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data; |
217 | }; |
218 | static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
219 | |
220 | struct JSClassMember |
221 | { |
222 | JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {} |
223 | |
224 | void set(quint32 nameOffset, bool isAccessor) |
225 | { |
226 | m_data.set<NameOffsetField>(nameOffset); |
227 | m_data.set<IsAccessorField>(isAccessor ? 1 : 0); |
228 | } |
229 | |
230 | quint32 nameOffset() const { return m_data.get<NameOffsetField>(); } |
231 | bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; } |
232 | |
233 | private: |
234 | using NameOffsetField = quint32_le_bitfield_member<0, 31>; |
235 | using IsAccessorField = quint32_le_bitfield_member<31, 1>; |
236 | quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data; |
237 | }; |
238 | static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
239 | |
240 | struct JSClass |
241 | { |
242 | quint32_le nMembers; |
243 | // JSClassMember[nMembers] |
244 | |
245 | static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; } |
246 | }; |
247 | static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
248 | |
249 | struct String |
250 | { |
251 | qint32_le size; |
252 | |
253 | static int calculateSize(const QString &str) { |
254 | // we cannot enconuter strings larger than INT_MAX anyway, as such a string |
255 | // would already break in other parts of the compilation process |
256 | return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7; |
257 | } |
258 | }; |
259 | |
260 | static_assert (sizeof (String) == 4, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
261 | |
262 | struct CodeOffsetToLineAndStatement { |
263 | quint32_le codeOffset; |
264 | qint32_le line; // signed because debug instructions get negative line numbers |
265 | quint32_le statement; |
266 | }; |
267 | static_assert(sizeof(CodeOffsetToLineAndStatement) == 12, "CodeOffsetToLineAndStatement structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
268 | |
269 | struct Block |
270 | { |
271 | quint32_le nLocals; |
272 | quint32_le localsOffset; |
273 | quint16_le sizeOfLocalTemporalDeadZone; |
274 | quint16_le padding; |
275 | |
276 | const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } |
277 | |
278 | static int calculateSize(int nLocals) { |
279 | int trailingData = nLocals*sizeof (quint32); |
280 | size_t size = align(a: align(a: sizeof(Block)) + size_t(trailingData)); |
281 | Q_ASSERT(size < INT_MAX); |
282 | return int(size); |
283 | } |
284 | |
285 | static size_t align(size_t a) { |
286 | return (a + 7) & ~size_t(7); |
287 | } |
288 | }; |
289 | static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
290 | |
291 | enum class NamedBuiltin: unsigned int { |
292 | Void, Var, Int, Bool, Real, String, Url, DateTime, RegExp |
293 | }; |
294 | |
295 | enum class CommonType : unsigned int { |
296 | // Actual named builtins |
297 | Void = uint(NamedBuiltin::Void), |
298 | Var = uint(NamedBuiltin::Var), |
299 | Int = uint(NamedBuiltin::Int), |
300 | Bool = uint(NamedBuiltin::Bool), |
301 | Real = uint(NamedBuiltin::Real), |
302 | String = uint(NamedBuiltin::String), |
303 | Url = uint(NamedBuiltin::Url), |
304 | DateTime = uint(NamedBuiltin::DateTime), |
305 | RegExp = uint(NamedBuiltin::RegExp), |
306 | |
307 | // Optimization for very common other types |
308 | Time, Date, Rect, Point, Size, |
309 | |
310 | // No type specified or not recognized |
311 | Invalid |
312 | }; |
313 | |
314 | struct ParameterType |
315 | { |
316 | enum Flag { |
317 | NoFlag = 0x0, |
318 | Common = 0x1, |
319 | List = 0x2, |
320 | }; |
321 | Q_DECLARE_FLAGS(Flags, Flag); |
322 | |
323 | void set(Flags flags, quint32 typeNameIndexOrCommonType) |
324 | { |
325 | m_data.set<IsListField>(flags.testFlag(flag: List) ? 1 : 0); |
326 | m_data.set<IndexIsCommonTypeField>(flags.testFlag(flag: Common) ? 1 : 0); |
327 | m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType); |
328 | } |
329 | |
330 | bool indexIsCommonType() const |
331 | { |
332 | return m_data.get<IndexIsCommonTypeField>() != 0; |
333 | } |
334 | |
335 | bool isList() const |
336 | { |
337 | return m_data.get<IsListField>() != 0; |
338 | } |
339 | |
340 | quint32 typeNameIndexOrCommonType() const |
341 | { |
342 | return m_data.get<TypeNameIndexOrCommonTypeField>(); |
343 | } |
344 | |
345 | private: |
346 | using IndexIsCommonTypeField = quint32_le_bitfield_member<0, 1>; |
347 | using IsListField = quint32_le_bitfield_member<1, 1>; |
348 | using TypeNameIndexOrCommonTypeField = quint32_le_bitfield_member<2, 30>; |
349 | quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data; |
350 | }; |
351 | static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
352 | |
353 | struct Parameter |
354 | { |
355 | quint32_le nameIndex; |
356 | ParameterType type; |
357 | }; |
358 | static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
359 | |
360 | // Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties |
361 | // for unaligned access. The ordering of the fields is also from largest to smallest. |
362 | struct Function |
363 | { |
364 | enum Flags : unsigned int { |
365 | IsStrict = 0x1, |
366 | IsArrowFunction = 0x2, |
367 | IsGenerator = 0x4, |
368 | IsClosureWrapper = 0x8, |
369 | }; |
370 | |
371 | // Absolute offset into file where the code for this function is located. |
372 | quint32_le codeOffset; |
373 | quint32_le codeSize; |
374 | |
375 | quint32_le nameIndex; |
376 | quint16_le length; |
377 | quint16_le nFormals; |
378 | quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData. |
379 | ParameterType returnType; |
380 | quint32_le localsOffset; |
381 | quint16_le nLocals; |
382 | quint16_le nLineAndStatementNumbers; |
383 | size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); } |
384 | quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers |
385 | |
386 | quint32_le nRegisters; |
387 | Location location; |
388 | quint32_le nLabelInfos; |
389 | |
390 | quint16_le sizeOfLocalTemporalDeadZone; |
391 | quint16_le firstTemporalDeadZoneRegister; |
392 | quint16_le sizeOfRegisterTemporalDeadZone; |
393 | |
394 | size_t labelInfosOffset() const |
395 | { |
396 | return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement); |
397 | } |
398 | |
399 | // Keep all unaligned data at the end |
400 | quint8 flags; |
401 | quint8 padding1; |
402 | |
403 | // quint32 formalsIndex[nFormals] |
404 | // quint32 localsIndex[nLocals] |
405 | |
406 | const Parameter *formalsTable() const |
407 | { |
408 | return reinterpret_cast<const Parameter *>( |
409 | reinterpret_cast<const char *>(this) + formalsOffset); |
410 | } |
411 | const quint32_le *localsTable() const |
412 | { |
413 | return reinterpret_cast<const quint32_le *>( |
414 | reinterpret_cast<const char *>(this) + localsOffset); |
415 | } |
416 | const CodeOffsetToLineAndStatement *lineAndStatementNumberTable() const |
417 | { |
418 | return reinterpret_cast<const CodeOffsetToLineAndStatement *>( |
419 | reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset()); |
420 | } |
421 | |
422 | // --- QQmlPropertyCacheCreator interface |
423 | const Parameter *formalsBegin() const { return formalsTable(); } |
424 | const Parameter *formalsEnd() const { return formalsTable() + nFormals; } |
425 | // --- |
426 | |
427 | const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); } |
428 | |
429 | const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; } |
430 | |
431 | static int calculateSize( |
432 | int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions, |
433 | int labelInfoSize, int codeSize) |
434 | { |
435 | int trailingData = nFormals * sizeof(Parameter) |
436 | + (nLocals + nInnerfunctions + labelInfoSize) * sizeof (quint32) |
437 | + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement); |
438 | size_t size = align(a: align(a: sizeof(Function)) + size_t(trailingData)) + align(a: codeSize); |
439 | Q_ASSERT(size < INT_MAX); |
440 | return int(size); |
441 | } |
442 | |
443 | static size_t align(size_t a) { |
444 | return (a + 7) & ~size_t(7); |
445 | } |
446 | }; |
447 | static_assert(sizeof(Function) == 56, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
448 | |
449 | struct Method { |
450 | enum Type { |
451 | Regular, |
452 | Getter, |
453 | Setter |
454 | }; |
455 | |
456 | quint32_le name; |
457 | quint32_le type; |
458 | quint32_le function; |
459 | }; |
460 | static_assert(sizeof(Method) == 12, "Method structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
461 | |
462 | struct Class |
463 | { |
464 | quint32_le nameIndex; |
465 | quint32_le scopeIndex; |
466 | quint32_le constructorFunction; |
467 | quint32_le nStaticMethods; |
468 | quint32_le nMethods; |
469 | quint32_le methodTableOffset; |
470 | |
471 | const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); } |
472 | |
473 | static int calculateSize(int nStaticMethods, int nMethods) { |
474 | int trailingData = (nStaticMethods + nMethods) * sizeof(Method); |
475 | size_t size = align(a: sizeof(Class) + trailingData); |
476 | Q_ASSERT(size < INT_MAX); |
477 | return int(size); |
478 | } |
479 | |
480 | static size_t align(size_t a) { |
481 | return (a + 7) & ~size_t(7); |
482 | } |
483 | }; |
484 | static_assert(sizeof(Class) == 24, "Class structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
485 | |
486 | struct TemplateObject |
487 | { |
488 | quint32_le size; |
489 | |
490 | static int calculateSize(int size) { |
491 | int trailingData = 2 * size * sizeof(quint32_le); |
492 | size_t s = align(a: sizeof(TemplateObject) + trailingData); |
493 | Q_ASSERT(s < INT_MAX); |
494 | return int(s); |
495 | } |
496 | |
497 | static size_t align(size_t a) { |
498 | return (a + 7) & ~size_t(7); |
499 | } |
500 | |
501 | const quint32_le *stringTable() const { |
502 | return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1)); |
503 | } |
504 | |
505 | uint stringIndexAt(uint i) const { |
506 | return stringTable()[i]; |
507 | } |
508 | uint rawStringIndexAt(uint i) const { |
509 | return stringTable()[size + i]; |
510 | } |
511 | }; |
512 | static_assert(sizeof(TemplateObject) == 4, "Template object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
513 | |
514 | struct ExportEntry |
515 | { |
516 | quint32_le exportName; |
517 | quint32_le moduleRequest; |
518 | quint32_le importName; |
519 | quint32_le localName; |
520 | Location location; |
521 | }; |
522 | static_assert(sizeof(ExportEntry) == 20, "ExportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
523 | |
524 | struct ImportEntry |
525 | { |
526 | quint32_le moduleRequest; |
527 | quint32_le importName; |
528 | quint32_le localName; |
529 | Location location; |
530 | }; |
531 | static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
532 | |
533 | // Qml data structures |
534 | |
535 | struct TranslationData |
536 | { |
537 | enum { NoContextIndex = std::numeric_limits<quint32>::max() }; |
538 | quint32_le stringIndex; |
539 | quint32_le commentIndex; |
540 | qint32_le number; |
541 | quint32_le contextIndex; |
542 | }; |
543 | static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
544 | |
545 | struct Binding |
546 | { |
547 | quint32_le propertyNameIndex; |
548 | |
549 | enum Type : unsigned int { |
550 | Type_Invalid, |
551 | Type_Boolean, |
552 | Type_Number, |
553 | Type_String, |
554 | Type_Null, |
555 | Type_Translation, |
556 | Type_TranslationById, |
557 | Type_Script, |
558 | Type_Object, |
559 | Type_AttachedProperty, |
560 | Type_GroupProperty |
561 | }; |
562 | |
563 | enum Flag : unsigned int { |
564 | IsSignalHandlerExpression = 0x1, |
565 | IsSignalHandlerObject = 0x2, |
566 | IsOnAssignment = 0x4, |
567 | InitializerForReadOnlyDeclaration = 0x8, |
568 | IsResolvedEnum = 0x10, |
569 | IsListItem = 0x20, |
570 | IsBindingToAlias = 0x40, |
571 | IsDeferredBinding = 0x80, |
572 | IsCustomParserBinding = 0x100, |
573 | IsFunctionExpression = 0x200, |
574 | IsPropertyObserver = 0x400 |
575 | }; |
576 | Q_DECLARE_FLAGS(Flags, Flag); |
577 | |
578 | using FlagsField = quint32_le_bitfield_member<0, 16>; |
579 | using TypeField = quint32_le_bitfield_member<16, 16>; |
580 | quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType; |
581 | |
582 | void clearFlags() { flagsAndType.set<FlagsField>(0); } |
583 | void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); } |
584 | bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; } |
585 | Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); } |
586 | |
587 | void setType(Type type) { flagsAndType.set<TypeField>(type); } |
588 | Type type() const { return Type(flagsAndType.get<TypeField>()); } |
589 | |
590 | union { |
591 | bool b; |
592 | quint32_le constantValueIndex; |
593 | quint32_le compiledScriptIndex; // used when Type_Script |
594 | quint32_le objectIndex; |
595 | quint32_le translationDataIndex; // used when Type_Translation |
596 | quint32 nullMarker; |
597 | } value; |
598 | quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings) |
599 | |
600 | Location location; |
601 | Location valueLocation; |
602 | |
603 | bool hasSignalHandlerBindingFlag() const |
604 | { |
605 | const Flags bindingFlags = flags(); |
606 | return bindingFlags & IsSignalHandlerExpression |
607 | || bindingFlags & IsSignalHandlerObject |
608 | || bindingFlags & IsPropertyObserver; |
609 | } |
610 | |
611 | bool isValueBinding() const |
612 | { |
613 | switch (type()) { |
614 | case Type_AttachedProperty: |
615 | case Type_GroupProperty: |
616 | return false; |
617 | default: |
618 | return !hasSignalHandlerBindingFlag(); |
619 | } |
620 | } |
621 | |
622 | bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(flag: IsBindingToAlias); } |
623 | bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(flag: IsBindingToAlias); } |
624 | |
625 | bool isSignalHandler() const |
626 | { |
627 | if (hasSignalHandlerBindingFlag()) { |
628 | Q_ASSERT(!isValueBinding()); |
629 | Q_ASSERT(!isAttachedProperty()); |
630 | Q_ASSERT(!isGroupProperty()); |
631 | return true; |
632 | } |
633 | return false; |
634 | } |
635 | |
636 | bool isAttachedProperty() const |
637 | { |
638 | if (type() == Type_AttachedProperty) { |
639 | Q_ASSERT(!isValueBinding()); |
640 | Q_ASSERT(!isSignalHandler()); |
641 | Q_ASSERT(!isGroupProperty()); |
642 | return true; |
643 | } |
644 | return false; |
645 | } |
646 | |
647 | bool isGroupProperty() const |
648 | { |
649 | if (type() == Type_GroupProperty) { |
650 | Q_ASSERT(!isValueBinding()); |
651 | Q_ASSERT(!isSignalHandler()); |
652 | Q_ASSERT(!isAttachedProperty()); |
653 | return true; |
654 | } |
655 | return false; |
656 | } |
657 | |
658 | bool isFunctionExpression() const { return hasFlag(flag: IsFunctionExpression); } |
659 | |
660 | //reverse of Lexer::singleEscape() |
661 | static QString escapedString(const QString &string) |
662 | { |
663 | QString tmp = QLatin1String("\""); |
664 | for (int i = 0; i < string.size(); ++i) { |
665 | const QChar &c = string.at(i); |
666 | switch (c.unicode()) { |
667 | case 0x08: |
668 | tmp += QLatin1String("\\b"); |
669 | break; |
670 | case 0x09: |
671 | tmp += QLatin1String("\\t"); |
672 | break; |
673 | case 0x0A: |
674 | tmp += QLatin1String("\\n"); |
675 | break; |
676 | case 0x0B: |
677 | tmp += QLatin1String("\\v"); |
678 | break; |
679 | case 0x0C: |
680 | tmp += QLatin1String("\\f"); |
681 | break; |
682 | case 0x0D: |
683 | tmp += QLatin1String("\\r"); |
684 | break; |
685 | case 0x22: |
686 | tmp += QLatin1String("\\\""); |
687 | break; |
688 | case 0x27: |
689 | tmp += QLatin1String("\\\'"); |
690 | break; |
691 | case 0x5C: |
692 | tmp += QLatin1String("\\\\"); |
693 | break; |
694 | default: |
695 | tmp += c; |
696 | break; |
697 | } |
698 | } |
699 | tmp += QLatin1Char('\"'); |
700 | return tmp; |
701 | } |
702 | |
703 | bool isTranslationBinding() const |
704 | { |
705 | const Binding::Type bindingType = type(); |
706 | return bindingType == Type_Translation || bindingType == Type_TranslationById; |
707 | } |
708 | bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); } |
709 | |
710 | bool isNumberBinding() const { return type() == Type_Number; } |
711 | |
712 | bool valueAsBoolean() const |
713 | { |
714 | if (type() == Type_Boolean) |
715 | return value.b; |
716 | return false; |
717 | } |
718 | }; |
719 | |
720 | static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
721 | |
722 | struct InlineComponent |
723 | { |
724 | quint32_le objectIndex; |
725 | quint32_le nameIndex; |
726 | Location location; |
727 | }; |
728 | |
729 | static_assert(sizeof(InlineComponent) == 12, "InlineComponent structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
730 | |
731 | struct EnumValue |
732 | { |
733 | quint32_le nameIndex; |
734 | qint32_le value; |
735 | Location location; |
736 | }; |
737 | static_assert(sizeof(EnumValue) == 12, "EnumValue structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
738 | |
739 | struct Enum |
740 | { |
741 | quint32_le nameIndex; |
742 | quint32_le nEnumValues; |
743 | Location location; |
744 | |
745 | const EnumValue *enumValueAt(int idx) const { |
746 | return reinterpret_cast<const EnumValue*>(this + 1) + idx; |
747 | } |
748 | |
749 | static int calculateSize(int nEnumValues) { |
750 | return (sizeof(Enum) |
751 | + nEnumValues * sizeof(EnumValue) |
752 | + 7) & ~0x7; |
753 | } |
754 | |
755 | // --- QQmlPropertyCacheCreatorInterface |
756 | const EnumValue *enumValuesBegin() const { return enumValueAt(idx: 0); } |
757 | const EnumValue *enumValuesEnd() const { return enumValueAt(idx: nEnumValues); } |
758 | int enumValueCount() const { return nEnumValues; } |
759 | // --- |
760 | }; |
761 | static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
762 | |
763 | struct Signal |
764 | { |
765 | quint32_le nameIndex; |
766 | quint32_le nParameters; |
767 | Location location; |
768 | // Parameter parameters[1]; |
769 | |
770 | const Parameter *parameterAt(int idx) const { |
771 | return reinterpret_cast<const Parameter*>(this + 1) + idx; |
772 | } |
773 | |
774 | static int calculateSize(int nParameters) { |
775 | return (sizeof(Signal) |
776 | + nParameters * sizeof(Parameter) |
777 | + 7) & ~0x7; |
778 | } |
779 | |
780 | // --- QQmlPropertyCacheCceatorInterface |
781 | const Parameter *parametersBegin() const { return parameterAt(idx: 0); } |
782 | const Parameter *parametersEnd() const { return parameterAt(idx: nParameters); } |
783 | int parameterCount() const { return nParameters; } |
784 | // --- |
785 | }; |
786 | static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
787 | |
788 | struct Property |
789 | { |
790 | private: |
791 | using CommonTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>; |
792 | using IsRequiredField = quint32_le_bitfield_member<28, 1>; |
793 | using IsCommonTypeField = quint32_le_bitfield_member<29, 1>; |
794 | using IsListField = quint32_le_bitfield_member<30, 1>; |
795 | using IsReadOnlyField = quint32_le_bitfield_member<31, 1>; |
796 | |
797 | public: |
798 | quint32_le nameIndex; |
799 | quint32_le_bitfield_union< |
800 | CommonTypeOrTypeNameIndexField, |
801 | IsRequiredField, |
802 | IsCommonTypeField, |
803 | IsListField, |
804 | IsReadOnlyField> data; |
805 | Location location; |
806 | |
807 | void setCommonType(CommonType t) |
808 | { |
809 | data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t)); |
810 | data.set<IsCommonTypeField>(true); |
811 | } |
812 | |
813 | CommonType commonType() const { |
814 | if (data.get<IsCommonTypeField>() != 0) |
815 | return CommonType(data.get<CommonTypeOrTypeNameIndexField>()); |
816 | return CommonType::Invalid; |
817 | } |
818 | |
819 | void setTypeNameIndex(int nameIndex) |
820 | { |
821 | data.set<CommonTypeOrTypeNameIndexField>(nameIndex); |
822 | data.set<IsCommonTypeField>(false); |
823 | } |
824 | |
825 | int typeNameIndex() const |
826 | { |
827 | return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>(); |
828 | } |
829 | |
830 | bool isCommonType() const { return data.get<IsCommonTypeField>(); } |
831 | uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); } |
832 | |
833 | bool isList() const { return data.get<IsListField>(); } |
834 | void setIsList(bool isList) { data.set<IsListField>(isList); } |
835 | |
836 | bool isRequired() const { return data.get<IsRequiredField>(); } |
837 | void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); } |
838 | |
839 | bool isReadOnly() const { return data.get<IsReadOnlyField>(); } |
840 | void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); } |
841 | }; |
842 | static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
843 | |
844 | struct RequiredPropertyExtraData { |
845 | quint32_le nameIndex; |
846 | }; |
847 | |
848 | static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
849 | |
850 | struct Alias { |
851 | private: |
852 | using NameIndexField = quint32_le_bitfield_member<0, 29>; |
853 | using FlagsField = quint32_le_bitfield_member<29, 3>; |
854 | |
855 | // object id index (in QQmlContextData::idValues) |
856 | using TargetObjectIdField = quint32_le_bitfield_member<0, 31>; |
857 | using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>; |
858 | using IdIndexField = quint32_le_bitfield_member<0, 32>; |
859 | |
860 | public: |
861 | |
862 | enum Flag : unsigned int { |
863 | IsReadOnly = 0x1, |
864 | Resolved = 0x2, |
865 | AliasPointsToPointerObject = 0x4 |
866 | }; |
867 | Q_DECLARE_FLAGS(Flags, Flag) |
868 | |
869 | quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags; |
870 | quint32_le_bitfield_union<IdIndexField, TargetObjectIdField, AliasToLocalAliasField> |
871 | idIndexAndTargetObjectIdAndAliasToLocalAlias; |
872 | |
873 | union { |
874 | quint32_le propertyNameIndex; // string index |
875 | qint32_le encodedMetaPropertyIndex; |
876 | quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId) |
877 | }; |
878 | Location location; |
879 | Location referenceLocation; |
880 | |
881 | bool hasFlag(Flag flag) const |
882 | { |
883 | return nameIndexAndFlags.get<FlagsField>() & flag; |
884 | } |
885 | |
886 | void setFlag(Flag flag) |
887 | { |
888 | nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag); |
889 | } |
890 | |
891 | void clearFlags() |
892 | { |
893 | nameIndexAndFlags.set<FlagsField>(0); |
894 | } |
895 | |
896 | quint32 nameIndex() const |
897 | { |
898 | return nameIndexAndFlags.get<NameIndexField>(); |
899 | } |
900 | |
901 | void setNameIndex(quint32 nameIndex) |
902 | { |
903 | nameIndexAndFlags.set<NameIndexField>(nameIndex); |
904 | } |
905 | |
906 | bool isObjectAlias() const |
907 | { |
908 | Q_ASSERT(hasFlag(Resolved)); |
909 | return encodedMetaPropertyIndex == -1; |
910 | } |
911 | |
912 | quint32 idIndex() const |
913 | { |
914 | return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<IdIndexField>(); |
915 | } |
916 | |
917 | void setIdIndex(quint32 idIndex) |
918 | { |
919 | idIndexAndTargetObjectIdAndAliasToLocalAlias.set<IdIndexField>(idIndex); |
920 | } |
921 | |
922 | |
923 | bool isAliasToLocalAlias() const |
924 | { |
925 | return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>(); |
926 | } |
927 | |
928 | void setIsAliasToLocalAlias(bool isAliasToLocalAlias) |
929 | { |
930 | idIndexAndTargetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias); |
931 | } |
932 | |
933 | quint32 targetObjectId() const |
934 | { |
935 | return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>(); |
936 | } |
937 | |
938 | void setTargetObjectId(quint32 targetObjectId) |
939 | { |
940 | idIndexAndTargetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId); |
941 | } |
942 | }; |
943 | static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
944 | |
945 | struct Object |
946 | { |
947 | private: |
948 | using FlagsField = quint32_le_bitfield_member<0, 15>; |
949 | using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>; |
950 | using IdField = quint32_le_bitfield_member<16, 16, qint32>; |
951 | public: |
952 | enum Flag : unsigned int { |
953 | NoFlag = 0x0, |
954 | IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary |
955 | HasDeferredBindings = 0x2, // any of the bindings are deferred |
956 | HasCustomParserBindings = 0x4, |
957 | IsInlineComponentRoot = 0x8, |
958 | IsPartOfInlineComponent = 0x10 |
959 | }; |
960 | Q_DECLARE_FLAGS(Flags, Flag); |
961 | |
962 | // Depending on the use, this may be the type name to instantiate before instantiating this |
963 | // object. For grouped properties the type name will be empty and for attached properties |
964 | // it will be the name of the attached type. |
965 | quint32_le inheritedTypeNameIndex; |
966 | quint32_le idNameIndex; |
967 | quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField> |
968 | flagsAndDefaultPropertyIsAliasAndId; |
969 | qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object |
970 | quint16_le nFunctions; |
971 | quint16_le nProperties; |
972 | quint32_le offsetToFunctions; |
973 | quint32_le offsetToProperties; |
974 | quint32_le offsetToAliases; |
975 | quint16_le nAliases; |
976 | quint16_le nEnums; |
977 | quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects |
978 | quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects |
979 | quint16_le nSignals; |
980 | quint16_le nBindings; |
981 | quint32_le offsetToBindings; |
982 | quint32_le nNamedObjectsInComponent; |
983 | quint32_le offsetToNamedObjectsInComponent; |
984 | Location location; |
985 | Location locationOfIdProperty; |
986 | quint32_le offsetToInlineComponents; |
987 | quint16_le nInlineComponents; |
988 | quint32_le offsetToRequiredPropertyExtraData; |
989 | quint16_le nRequiredPropertyExtraData; |
990 | // Function[] |
991 | // Property[] |
992 | // Signal[] |
993 | // Binding[] |
994 | // InlineComponent[] |
995 | // RequiredPropertyExtraData[] |
996 | |
997 | Flags flags() const |
998 | { |
999 | return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>()); |
1000 | } |
1001 | |
1002 | bool hasFlag(Flag flag) const |
1003 | { |
1004 | return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag; |
1005 | } |
1006 | |
1007 | void setFlag(Flag flag) |
1008 | { |
1009 | flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>( |
1010 | flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag); |
1011 | } |
1012 | |
1013 | void setFlags(Flags flags) |
1014 | { |
1015 | flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags); |
1016 | } |
1017 | |
1018 | bool hasAliasAsDefaultProperty() const |
1019 | { |
1020 | return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>(); |
1021 | } |
1022 | |
1023 | void setHasAliasAsDefaultProperty(bool defaultAlias) |
1024 | { |
1025 | flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias); |
1026 | } |
1027 | |
1028 | qint32 objectId() const |
1029 | { |
1030 | return flagsAndDefaultPropertyIsAliasAndId.get<IdField>(); |
1031 | } |
1032 | |
1033 | void setObjectId(qint32 id) |
1034 | { |
1035 | flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id); |
1036 | } |
1037 | |
1038 | |
1039 | static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData) |
1040 | { |
1041 | return ( sizeof(Object) |
1042 | + nFunctions * sizeof(quint32) |
1043 | + nProperties * sizeof(Property) |
1044 | + nAliases * sizeof(Alias) |
1045 | + nEnums * sizeof(quint32) |
1046 | + nSignals * sizeof(quint32) |
1047 | + nBindings * sizeof(Binding) |
1048 | + nNamedObjectsInComponent * sizeof(int) |
1049 | + nInlineComponents * sizeof(InlineComponent) |
1050 | + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData) |
1051 | + 0x7 |
1052 | ) & ~0x7; |
1053 | } |
1054 | |
1055 | const quint32_le *functionOffsetTable() const |
1056 | { |
1057 | return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions); |
1058 | } |
1059 | |
1060 | const Property *propertyTable() const |
1061 | { |
1062 | return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); |
1063 | } |
1064 | |
1065 | const Alias *aliasTable() const |
1066 | { |
1067 | return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); |
1068 | } |
1069 | |
1070 | const Binding *bindingTable() const |
1071 | { |
1072 | return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); |
1073 | } |
1074 | |
1075 | const Enum *enumAt(int idx) const |
1076 | { |
1077 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums); |
1078 | const quint32_le offset = offsetTable[idx]; |
1079 | return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset); |
1080 | } |
1081 | |
1082 | const Signal *signalAt(int idx) const |
1083 | { |
1084 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals); |
1085 | const quint32_le offset = offsetTable[idx]; |
1086 | return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset); |
1087 | } |
1088 | |
1089 | const InlineComponent *inlineComponentAt(int idx) const |
1090 | { |
1091 | return inlineComponentTable() + idx; |
1092 | } |
1093 | |
1094 | const quint32_le *namedObjectsInComponentTable() const |
1095 | { |
1096 | return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); |
1097 | } |
1098 | |
1099 | const InlineComponent *inlineComponentTable() const |
1100 | { |
1101 | return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents); |
1102 | } |
1103 | |
1104 | const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const |
1105 | { |
1106 | return requiredPropertyExtraDataTable() + idx; |
1107 | } |
1108 | |
1109 | const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const |
1110 | { |
1111 | return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData); |
1112 | } |
1113 | |
1114 | // --- QQmlPropertyCacheCreator interface |
1115 | int propertyCount() const { return nProperties; } |
1116 | int aliasCount() const { return nAliases; } |
1117 | int enumCount() const { return nEnums; } |
1118 | int signalCount() const { return nSignals; } |
1119 | int functionCount() const { return nFunctions; } |
1120 | |
1121 | const Binding *bindingsBegin() const { return bindingTable(); } |
1122 | const Binding *bindingsEnd() const { return bindingTable() + nBindings; } |
1123 | int bindingCount() const { return nBindings; } |
1124 | |
1125 | const Property *propertiesBegin() const { return propertyTable(); } |
1126 | const Property *propertiesEnd() const { return propertyTable() + nProperties; } |
1127 | |
1128 | const Alias *aliasesBegin() const { return aliasTable(); } |
1129 | const Alias *aliasesEnd() const { return aliasTable() + nAliases; } |
1130 | |
1131 | typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator; |
1132 | EnumIterator enumsBegin() const { return EnumIterator(this, 0); } |
1133 | EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); } |
1134 | |
1135 | typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator; |
1136 | SignalIterator signalsBegin() const { return SignalIterator(this, 0); } |
1137 | SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); } |
1138 | |
1139 | typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator; |
1140 | InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);} |
1141 | InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);} |
1142 | |
1143 | typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator; |
1144 | RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); } |
1145 | RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); } |
1146 | |
1147 | int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; } |
1148 | // --- |
1149 | }; |
1150 | static_assert(sizeof(Object) == 84, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
1151 | |
1152 | struct Import |
1153 | { |
1154 | enum ImportType : unsigned int { |
1155 | ImportLibrary = 0x1, |
1156 | ImportFile = 0x2, |
1157 | ImportScript = 0x3, |
1158 | ImportInlineComponent = 0x4 |
1159 | }; |
1160 | quint32_le type; |
1161 | |
1162 | quint32_le uriIndex; |
1163 | quint32_le qualifierIndex; |
1164 | |
1165 | Location location; |
1166 | QTypeRevision version; |
1167 | quint16_le reserved; |
1168 | |
1169 | Import() |
1170 | { |
1171 | type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0; |
1172 | } |
1173 | }; |
1174 | static_assert(sizeof(Import) == 20, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
1175 | |
1176 | struct QmlUnit |
1177 | { |
1178 | quint32_le nImports; |
1179 | quint32_le offsetToImports; |
1180 | quint32_le nObjects; |
1181 | quint32_le offsetToObjects; |
1182 | |
1183 | const Import *importAt(int idx) const { |
1184 | return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); |
1185 | } |
1186 | |
1187 | const Object *objectAt(int idx) const { |
1188 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects); |
1189 | const quint32_le offset = offsetTable[idx]; |
1190 | return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset); |
1191 | } |
1192 | }; |
1193 | static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
1194 | |
1195 | enum { QmlCompileHashSpace = 48 }; |
1196 | static const char magic_str[] = "qv4cdata"; |
1197 | |
1198 | struct Unit |
1199 | { |
1200 | // DO NOT CHANGE THESE FIELDS EVER |
1201 | char magic[8]; |
1202 | quint32_le version; |
1203 | quint32_le qtVersion; |
1204 | qint64_le sourceTimeStamp; |
1205 | quint32_le unitSize; // Size of the Unit and any depending data. |
1206 | // END DO NOT CHANGE THESE FIELDS EVER |
1207 | |
1208 | char libraryVersionHash[QmlCompileHashSpace]; |
1209 | |
1210 | char md5Checksum[16]; // checksum of all bytes following this field. |
1211 | char dependencyMD5Checksum[16]; |
1212 | |
1213 | enum : unsigned int { |
1214 | IsJavascript = 0x1, |
1215 | StaticData = 0x2, // Unit data persistent in memory? |
1216 | IsSingleton = 0x4, |
1217 | IsSharedLibrary = 0x8, // .pragma shared? |
1218 | IsESModule = 0x10, |
1219 | PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation |
1220 | IsStrict = 0x40, |
1221 | ListPropertyAssignReplaceIfDefault = 0x80, |
1222 | ListPropertyAssignReplaceIfNotDefault = 0x100, |
1223 | ListPropertyAssignReplace |
1224 | = ListPropertyAssignReplaceIfDefault | ListPropertyAssignReplaceIfNotDefault, |
1225 | ComponentsBound = 0x200, |
1226 | FunctionSignaturesIgnored = 0x400, |
1227 | NativeMethodsAcceptThisObject = 0x800, |
1228 | ValueTypesCopied = 0x1000, |
1229 | ValueTypesAddressable = 0x2000, |
1230 | ValueTypesAssertable = 0x4000, |
1231 | }; |
1232 | quint32_le flags; |
1233 | quint32_le stringTableSize; |
1234 | quint32_le offsetToStringTable; |
1235 | quint32_le functionTableSize; |
1236 | quint32_le offsetToFunctionTable; |
1237 | quint32_le classTableSize; |
1238 | quint32_le offsetToClassTable; |
1239 | quint32_le templateObjectTableSize; |
1240 | quint32_le offsetToTemplateObjectTable; |
1241 | quint32_le blockTableSize; |
1242 | quint32_le offsetToBlockTable; |
1243 | quint32_le lookupTableSize; |
1244 | quint32_le offsetToLookupTable; |
1245 | quint32_le regexpTableSize; |
1246 | quint32_le offsetToRegexpTable; |
1247 | quint32_le constantTableSize; |
1248 | quint32_le offsetToConstantTable; |
1249 | quint32_le jsClassTableSize; |
1250 | quint32_le offsetToJSClassTable; |
1251 | quint32_le translationTableSize; |
1252 | quint32_le offsetToTranslationTable; |
1253 | quint32_le localExportEntryTableSize; |
1254 | quint32_le offsetToLocalExportEntryTable; |
1255 | quint32_le indirectExportEntryTableSize; |
1256 | quint32_le offsetToIndirectExportEntryTable; |
1257 | quint32_le starExportEntryTableSize; |
1258 | quint32_le offsetToStarExportEntryTable; |
1259 | quint32_le importEntryTableSize; |
1260 | quint32_le offsetToImportEntryTable; |
1261 | quint32_le moduleRequestTableSize; |
1262 | quint32_le offsetToModuleRequestTable; |
1263 | qint32_le indexOfRootFunction; |
1264 | quint32_le sourceFileIndex; |
1265 | quint32_le finalUrlIndex; |
1266 | |
1267 | quint32_le offsetToQmlUnit; |
1268 | |
1269 | /* QML specific fields */ |
1270 | |
1271 | const QmlUnit *qmlUnit() const { |
1272 | return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit); |
1273 | } |
1274 | |
1275 | QmlUnit *qmlUnit() { |
1276 | return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit); |
1277 | } |
1278 | |
1279 | bool isSingleton() const { |
1280 | return flags & Unit::IsSingleton; |
1281 | } |
1282 | /* end QML specific fields*/ |
1283 | |
1284 | QString stringAtInternal(uint idx) const { |
1285 | Q_ASSERT(idx < stringTableSize); |
1286 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable); |
1287 | const quint32_le offset = offsetTable[idx]; |
1288 | const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset); |
1289 | Q_ASSERT(str->size >= 0); |
1290 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
1291 | const QChar *characters = reinterpret_cast<const QChar *>(str + 1); |
1292 | if (flags & StaticData) |
1293 | return QString::fromRawData(characters, size: str->size); |
1294 | return QString(characters, str->size); |
1295 | #else |
1296 | const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1); |
1297 | QString qstr(str->size, Qt::Uninitialized); |
1298 | QChar *ch = qstr.data(); |
1299 | for (int i = 0; i < str->size; ++i) |
1300 | ch[i] = QChar(characters[i]); |
1301 | return qstr; |
1302 | #endif |
1303 | } |
1304 | |
1305 | const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); } |
1306 | const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); } |
1307 | const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); } |
1308 | const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); } |
1309 | |
1310 | const Function *functionAt(int idx) const { |
1311 | const quint32_le *offsetTable = functionOffsetTable(); |
1312 | const quint32_le offset = offsetTable[idx]; |
1313 | return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset); |
1314 | } |
1315 | |
1316 | const Class *classAt(int idx) const { |
1317 | const quint32_le *offsetTable = classOffsetTable(); |
1318 | const quint32_le offset = offsetTable[idx]; |
1319 | return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset); |
1320 | } |
1321 | |
1322 | const TemplateObject *templateObjectAt(int idx) const { |
1323 | const quint32_le *offsetTable = templateObjectOffsetTable(); |
1324 | const quint32_le offset = offsetTable[idx]; |
1325 | return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset); |
1326 | } |
1327 | |
1328 | const Block *blockAt(int idx) const { |
1329 | const quint32_le *offsetTable = blockOffsetTable(); |
1330 | const quint32_le offset = offsetTable[idx]; |
1331 | return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset); |
1332 | } |
1333 | |
1334 | const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); } |
1335 | const RegExp *regexpAt(int index) const { |
1336 | return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp)); |
1337 | } |
1338 | const quint64_le *constants() const { |
1339 | return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable); |
1340 | } |
1341 | |
1342 | const JSClassMember *jsClassAt(int idx, int *nMembers) const { |
1343 | const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable); |
1344 | const quint32_le offset = offsetTable[idx]; |
1345 | const char *ptr = reinterpret_cast<const char *>(this) + offset; |
1346 | const JSClass *klass = reinterpret_cast<const JSClass *>(ptr); |
1347 | *nMembers = klass->nMembers; |
1348 | return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass)); |
1349 | } |
1350 | |
1351 | const TranslationData *translations() const { |
1352 | return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable); |
1353 | } |
1354 | |
1355 | const quint32_le *translationContextIndex() const{ |
1356 | if ( translationTableSize == 0) |
1357 | return nullptr; |
1358 | return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) |
1359 | + offsetToTranslationTable |
1360 | + translationTableSize * sizeof(CompiledData::TranslationData)); } |
1361 | |
1362 | quint32_le *translationContextIndex() { |
1363 | if ( translationTableSize == 0) |
1364 | return nullptr; |
1365 | return reinterpret_cast<quint32_le*>((reinterpret_cast<char *>(this)) |
1366 | + offsetToTranslationTable |
1367 | + translationTableSize * sizeof(CompiledData::TranslationData)); } |
1368 | |
1369 | const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); } |
1370 | const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); } |
1371 | const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); } |
1372 | const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); } |
1373 | |
1374 | const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); } |
1375 | |
1376 | bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const; |
1377 | }; |
1378 | |
1379 | static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
1380 | |
1381 | struct TypeReference |
1382 | { |
1383 | TypeReference(const Location &loc) |
1384 | : location(loc) |
1385 | , needsCreation(false) |
1386 | , errorWhenNotFound(false) |
1387 | {} |
1388 | Location location; // first use |
1389 | bool needsCreation : 1; // whether the type needs to be creatable or not |
1390 | bool errorWhenNotFound: 1; |
1391 | }; |
1392 | |
1393 | // Map from name index to location of first use. |
1394 | struct TypeReferenceMap : QHash<int, TypeReference> |
1395 | { |
1396 | TypeReference &add(int nameIndex, const Location &loc) { |
1397 | Iterator it = find(key: nameIndex); |
1398 | if (it != end()) |
1399 | return *it; |
1400 | return *insert(key: nameIndex, value: loc); |
1401 | } |
1402 | |
1403 | template <typename CompiledObject> |
1404 | void collectFromObject(const CompiledObject *obj) |
1405 | { |
1406 | if (obj->inheritedTypeNameIndex != 0) { |
1407 | TypeReference &r = this->add(nameIndex: obj->inheritedTypeNameIndex, loc: obj->location); |
1408 | r.needsCreation = true; |
1409 | r.errorWhenNotFound = true; |
1410 | } |
1411 | |
1412 | auto prop = obj->propertiesBegin(); |
1413 | auto const propEnd = obj->propertiesEnd(); |
1414 | for ( ; prop != propEnd; ++prop) { |
1415 | if (!prop->isCommonType()) { |
1416 | TypeReference &r = this->add(nameIndex: prop->commonTypeOrTypeNameIndex(), loc: prop->location); |
1417 | r.errorWhenNotFound = true; |
1418 | } |
1419 | } |
1420 | |
1421 | auto binding = obj->bindingsBegin(); |
1422 | auto const bindingEnd = obj->bindingsEnd(); |
1423 | for ( ; binding != bindingEnd; ++binding) { |
1424 | if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) |
1425 | this->add(nameIndex: binding->propertyNameIndex, loc: binding->location); |
1426 | } |
1427 | |
1428 | auto ic = obj->inlineComponentsBegin(); |
1429 | auto const icEnd = obj->inlineComponentsEnd(); |
1430 | for (; ic != icEnd; ++ic) { |
1431 | this->add(nameIndex: ic->nameIndex, loc: ic->location); |
1432 | } |
1433 | } |
1434 | |
1435 | template <typename Iterator> |
1436 | void collectFromObjects(Iterator it, Iterator end) |
1437 | { |
1438 | for (; it != end; ++it) |
1439 | collectFromObject(*it); |
1440 | } |
1441 | }; |
1442 | |
1443 | using DependentTypesHasher = std::function<QByteArray()>; |
1444 | |
1445 | struct InlineComponentData { |
1446 | |
1447 | InlineComponentData() = default; |
1448 | InlineComponentData( |
1449 | const QQmlType &qmlType, int objectIndex, int nameIndex, int totalObjectCount, |
1450 | int totalBindingCount, int totalParserStatusCount) |
1451 | : qmlType(qmlType) |
1452 | , objectIndex(objectIndex) |
1453 | , nameIndex(nameIndex) |
1454 | , totalObjectCount(totalObjectCount) |
1455 | , totalBindingCount(totalBindingCount) |
1456 | , totalParserStatusCount(totalParserStatusCount) |
1457 | {} |
1458 | |
1459 | QQmlType qmlType; |
1460 | int objectIndex = -1; |
1461 | int nameIndex = -1; |
1462 | int totalObjectCount = 0; |
1463 | int totalBindingCount = 0; |
1464 | int totalParserStatusCount = 0; |
1465 | }; |
1466 | |
1467 | struct CompilationUnit final : public QQmlRefCounted<CompilationUnit> |
1468 | { |
1469 | Q_DISABLE_COPY_MOVE(CompilationUnit) |
1470 | |
1471 | const Unit *data = nullptr; |
1472 | const QmlUnit *qmlData = nullptr; |
1473 | QStringList dynamicStrings; |
1474 | const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions = nullptr; |
1475 | |
1476 | // pointers either to data->constants() or little-endian memory copy. |
1477 | const StaticValue *constants = nullptr; |
1478 | |
1479 | std::unique_ptr<CompilationUnitMapper> backingFile; |
1480 | |
1481 | int m_totalBindingsCount = 0; // Number of bindings used in this type |
1482 | int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses |
1483 | int m_totalObjectCount = 0; // Number of objects explicitly instantiated |
1484 | |
1485 | std::unique_ptr<QString> icRootName; |
1486 | QHash<QString, InlineComponentData> inlineComponentData; |
1487 | |
1488 | // index is object index. This allows fast access to the |
1489 | // property data when initializing bindings, avoiding expensive |
1490 | // lookups by string (property name). |
1491 | QVector<BindingPropertyData> bindingPropertyDataPerObject; |
1492 | |
1493 | ResolvedTypeReferenceMap resolvedTypes; |
1494 | QQmlRefPointer<QQmlTypeNameCache> typeNameCache; |
1495 | |
1496 | QQmlPropertyCacheVector propertyCaches; |
1497 | |
1498 | QQmlType qmlType; |
1499 | |
1500 | QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts; |
1501 | |
1502 | public: |
1503 | // --- interface for QQmlPropertyCacheCreator |
1504 | using CompiledObject = const CompiledData::Object; |
1505 | using CompiledFunction = const CompiledData::Function; |
1506 | using CompiledBinding = const CompiledData::Binding; |
1507 | |
1508 | // Empty dummy. We don't need to do this when loading from cache. |
1509 | class IdToObjectMap |
1510 | { |
1511 | public: |
1512 | void insert(int, int) {} |
1513 | void clear() {} |
1514 | |
1515 | // We have already checked uniqueness of IDs when creating the CU |
1516 | bool contains(int) { return false; } |
1517 | }; |
1518 | |
1519 | explicit CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions, |
1520 | const QString &fileName = QString(), const QString &finalUrlString = QString()) |
1521 | : CompilationUnit(unitData, fileName, finalUrlString) |
1522 | { |
1523 | this->aotCompiledFunctions = aotCompiledFunctions; |
1524 | } |
1525 | |
1526 | Q_QML_EXPORT CompilationUnit( |
1527 | const Unit *unitData = nullptr, const QString &fileName = QString(), |
1528 | const QString &finalUrlString = QString()); |
1529 | |
1530 | Q_QML_EXPORT ~CompilationUnit(); |
1531 | |
1532 | const Unit *unitData() const { return data; } |
1533 | |
1534 | void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr, |
1535 | const QString &fileName = QString(), const QString &finalUrlString = QString()) |
1536 | { |
1537 | data = unitData; |
1538 | qmlData = nullptr; |
1539 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1540 | delete [] constants; |
1541 | #endif |
1542 | constants = nullptr; |
1543 | m_fileName.clear(); |
1544 | m_finalUrlString.clear(); |
1545 | if (!data) |
1546 | return; |
1547 | |
1548 | qmlData = qmlUnit ? qmlUnit : data->qmlUnit(); |
1549 | |
1550 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
1551 | StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize]; |
1552 | const quint64_le *littleEndianConstants = data->constants(); |
1553 | for (uint i = 0; i < data->constantTableSize; ++i) |
1554 | bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]); |
1555 | constants = bigEndianConstants; |
1556 | #else |
1557 | constants = reinterpret_cast<const StaticValue*>(data->constants()); |
1558 | #endif |
1559 | |
1560 | m_fileName = !fileName.isEmpty() ? fileName : stringAt(index: data->sourceFileIndex); |
1561 | m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(index: data->finalUrlIndex); |
1562 | } |
1563 | |
1564 | QString stringAt(uint index) const |
1565 | { |
1566 | if (index < data->stringTableSize) |
1567 | return data->stringAtInternal(idx: index); |
1568 | |
1569 | const qsizetype dynamicIndex = index - data->stringTableSize; |
1570 | Q_ASSERT(dynamicIndex < dynamicStrings.size()); |
1571 | return dynamicStrings.at(i: dynamicIndex); |
1572 | } |
1573 | |
1574 | QString fileName() const { return m_fileName; } |
1575 | QString finalUrlString() const { return m_finalUrlString; } |
1576 | |
1577 | QString bindingValueAsString(const CompiledData::Binding *binding) const |
1578 | { |
1579 | using namespace CompiledData; |
1580 | switch (binding->type()) { |
1581 | case Binding::Type_Script: |
1582 | case Binding::Type_String: |
1583 | return stringAt(index: binding->stringIndex); |
1584 | case Binding::Type_Null: |
1585 | return QStringLiteral("null"); |
1586 | case Binding::Type_Boolean: |
1587 | return binding->value.b ? QStringLiteral("true") : QStringLiteral( "false"); |
1588 | case Binding::Type_Number: |
1589 | return QString::number(bindingValueAsNumber(binding), format: 'g', precision: QLocale::FloatingPointShortest); |
1590 | case Binding::Type_Invalid: |
1591 | return QString(); |
1592 | case Binding::Type_TranslationById: |
1593 | case Binding::Type_Translation: |
1594 | return stringAt(index: data->translations()[binding->value.translationDataIndex].stringIndex); |
1595 | default: |
1596 | break; |
1597 | } |
1598 | return QString(); |
1599 | } |
1600 | |
1601 | QString bindingValueAsScriptString(const CompiledData::Binding *binding) const |
1602 | { |
1603 | return (binding->type() == CompiledData::Binding::Type_String) |
1604 | ? CompiledData::Binding::escapedString(string: stringAt(index: binding->stringIndex)) |
1605 | : bindingValueAsString(binding); |
1606 | } |
1607 | |
1608 | double bindingValueAsNumber(const CompiledData::Binding *binding) const |
1609 | { |
1610 | if (binding->type() != CompiledData::Binding::Type_Number) |
1611 | return 0.0; |
1612 | return constants[binding->value.constantValueIndex].doubleValue(); |
1613 | } |
1614 | |
1615 | Q_QML_EXPORT static QString localCacheFilePath(const QUrl &url); |
1616 | Q_QML_EXPORT bool loadFromDisk( |
1617 | const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString); |
1618 | Q_QML_EXPORT bool saveToDisk(const QUrl &unitUrl, QString *errorString); |
1619 | |
1620 | int importCount() const { return qmlData->nImports; } |
1621 | const CompiledData::Import *importAt(int index) const { return qmlData->importAt(idx: index); } |
1622 | |
1623 | Q_QML_EXPORT QStringList moduleRequests() const; |
1624 | |
1625 | // url() and fileName() shall be used to load the actual QML/JS code or to show errors or |
1626 | // warnings about that code. They include any potential URL interceptions and thus represent the |
1627 | // "physical" location of the code. |
1628 | // |
1629 | // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code |
1630 | // They are _not_ intercepted and thus represent the "logical" name for the code. |
1631 | |
1632 | QUrl url() const |
1633 | { |
1634 | if (!m_url.isValid()) |
1635 | m_url = QUrl(fileName()); |
1636 | return m_url; |
1637 | } |
1638 | |
1639 | QUrl finalUrl() const |
1640 | { |
1641 | if (!m_finalUrl.isValid()) |
1642 | m_finalUrl = QUrl(finalUrlString()); |
1643 | return m_finalUrl; |
1644 | } |
1645 | |
1646 | ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(key: id); } |
1647 | ResolvedTypeReference *resolvedType(QMetaType type) const; |
1648 | |
1649 | QQmlPropertyCache::ConstPtr rootPropertyCache() const |
1650 | { |
1651 | return propertyCaches.at(/*root object*/index: 0); |
1652 | } |
1653 | |
1654 | int objectCount() const { return qmlData->nObjects; } |
1655 | const CompiledObject *objectAt(int index) const { return qmlData->objectAt(idx: index); } |
1656 | |
1657 | int totalBindingsCount() const; |
1658 | int totalParserStatusCount() const; |
1659 | int totalObjectCount() const; |
1660 | |
1661 | int inlineComponentId(const QString &inlineComponentName) const |
1662 | { |
1663 | for (uint i = 0; i < qmlData->nObjects; ++i) { |
1664 | auto *object = qmlData->objectAt(idx: i); |
1665 | for (auto it = object->inlineComponentsBegin(), end = object->inlineComponentsEnd(); |
1666 | it != end; ++it) { |
1667 | if (stringAt(index: it->nameIndex) == inlineComponentName) |
1668 | return it->objectIndex; |
1669 | } |
1670 | } |
1671 | return -1; |
1672 | } |
1673 | |
1674 | void finalizeCompositeType(const QQmlType &type); |
1675 | |
1676 | bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; |
1677 | |
1678 | enum class ListPropertyAssignBehavior { Append, Replace, ReplaceIfNotDefault }; |
1679 | ListPropertyAssignBehavior listPropertyAssignBehavior() const |
1680 | { |
1681 | if (unitData()->flags & CompiledData::Unit::ListPropertyAssignReplace) |
1682 | return ListPropertyAssignBehavior::Replace; |
1683 | if (unitData()->flags & CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault) |
1684 | return ListPropertyAssignBehavior::ReplaceIfNotDefault; |
1685 | return ListPropertyAssignBehavior::Append; |
1686 | } |
1687 | |
1688 | bool ignoresFunctionSignature() const |
1689 | { |
1690 | return unitData()->flags & CompiledData::Unit::FunctionSignaturesIgnored; |
1691 | } |
1692 | |
1693 | bool nativeMethodsAcceptThisObjects() const |
1694 | { |
1695 | return unitData()->flags & CompiledData::Unit::NativeMethodsAcceptThisObject; |
1696 | } |
1697 | |
1698 | bool valueTypesAreCopied() const |
1699 | { |
1700 | return unitData()->flags & CompiledData::Unit::ValueTypesCopied; |
1701 | } |
1702 | |
1703 | bool valueTypesAreAddressable() const |
1704 | { |
1705 | return unitData()->flags & CompiledData::Unit::ValueTypesAddressable; |
1706 | } |
1707 | |
1708 | bool valueTypesAreAssertable() const |
1709 | { |
1710 | return unitData()->flags & CompiledData::Unit::ValueTypesAssertable; |
1711 | } |
1712 | |
1713 | bool componentsAreBound() const |
1714 | { |
1715 | return unitData()->flags & CompiledData::Unit::ComponentsBound; |
1716 | } |
1717 | |
1718 | bool isESModule() const |
1719 | { |
1720 | return unitData()->flags & CompiledData::Unit::IsESModule; |
1721 | } |
1722 | |
1723 | bool isSharedLibrary() const |
1724 | { |
1725 | return unitData()->flags & CompiledData::Unit::IsSharedLibrary; |
1726 | } |
1727 | |
1728 | struct FunctionIterator |
1729 | { |
1730 | FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index) |
1731 | : unit(unit), object(object), index(index) {} |
1732 | const CompiledData::Unit *unit; |
1733 | const CompiledObject *object; |
1734 | int index; |
1735 | |
1736 | const CompiledFunction *operator->() const |
1737 | { |
1738 | return unit->functionAt(idx: object->functionOffsetTable()[index]); |
1739 | } |
1740 | |
1741 | void operator++() { ++index; } |
1742 | bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; } |
1743 | bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; } |
1744 | }; |
1745 | |
1746 | FunctionIterator objectFunctionsBegin(const CompiledObject *object) const |
1747 | { |
1748 | return FunctionIterator(unitData(), object, 0); |
1749 | } |
1750 | |
1751 | FunctionIterator objectFunctionsEnd(const CompiledObject *object) const |
1752 | { |
1753 | return FunctionIterator(unitData(), object, object->nFunctions); |
1754 | } |
1755 | |
1756 | QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const; |
1757 | QMetaType metaType() const { return qmlType.typeId(); } |
1758 | |
1759 | private: |
1760 | QString m_fileName; // initialized from data->sourceFileIndex |
1761 | QString m_finalUrlString; // initialized from data->finalUrlIndex |
1762 | |
1763 | mutable QQmlNullableValue<QUrl> m_url; |
1764 | mutable QQmlNullableValue<QUrl> m_finalUrl; |
1765 | }; |
1766 | |
1767 | class SaveableUnitPointer |
1768 | { |
1769 | Q_DISABLE_COPY_MOVE(SaveableUnitPointer) |
1770 | public: |
1771 | SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) : |
1772 | unit(unit), |
1773 | temporaryFlags(temporaryFlags) |
1774 | { |
1775 | } |
1776 | |
1777 | ~SaveableUnitPointer() = default; |
1778 | |
1779 | template<typename Char> |
1780 | bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const |
1781 | { |
1782 | const quint32_le oldFlags = mutableFlags(); |
1783 | auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; }); |
1784 | mutableFlags() |= temporaryFlags; |
1785 | return writer(data<Char>(), size()); |
1786 | } |
1787 | |
1788 | static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size, |
1789 | QString *errorString) |
1790 | { |
1791 | #if QT_CONFIG(temporaryfile) |
1792 | QSaveFile cacheFile(outputFileName); |
1793 | if (!cacheFile.open(flags: QIODevice::WriteOnly | QIODevice::Truncate) |
1794 | || cacheFile.write(data, len: size) != size |
1795 | || !cacheFile.commit()) { |
1796 | *errorString = cacheFile.errorString(); |
1797 | return false; |
1798 | } |
1799 | |
1800 | errorString->clear(); |
1801 | return true; |
1802 | #else |
1803 | Q_UNUSED(outputFileName); |
1804 | *errorString = QStringLiteral("features.temporaryfile is disabled."); |
1805 | return false; |
1806 | #endif |
1807 | } |
1808 | |
1809 | private: |
1810 | const Unit *unit; |
1811 | quint32 temporaryFlags; |
1812 | |
1813 | quint32_le &mutableFlags() const |
1814 | { |
1815 | return const_cast<Unit *>(unit)->flags; |
1816 | } |
1817 | |
1818 | template<typename Char> |
1819 | const Char *data() const |
1820 | { |
1821 | Q_STATIC_ASSERT(sizeof(Char) == 1); |
1822 | const Char *dataPtr; |
1823 | memcpy(&dataPtr, &unit, sizeof(dataPtr)); |
1824 | return dataPtr; |
1825 | } |
1826 | |
1827 | quint32 size() const |
1828 | { |
1829 | return unit->unitSize; |
1830 | } |
1831 | }; |
1832 | |
1833 | |
1834 | } // CompiledData namespace |
1835 | } // QV4 namespace |
1836 | |
1837 | Q_DECLARE_OPERATORS_FOR_FLAGS(QV4::CompiledData::ParameterType::Flags); |
1838 | Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE); |
1839 | |
1840 | QT_END_NAMESPACE |
1841 | |
1842 | #endif |
1843 |
Definitions
- ResolvedTypeReferenceMap
- TableIterator
- TableIterator
- operator->
- operator*
- operator++
- operator==
- operator!=
- Location
- Location
- Location
- operator<
- qHash
- operator==
- set
- line
- column
- RegExp
- Flags
- RegExp
- RegExp
- flags
- stringIndex
- Lookup
- Type
- Mode
- type
- nameIndex
- mode
- Lookup
- Lookup
- JSClassMember
- JSClassMember
- set
- nameOffset
- isAccessor
- JSClass
- calculateSize
- String
- calculateSize
- CodeOffsetToLineAndStatement
- Block
- localsTable
- calculateSize
- align
- NamedBuiltin
- CommonType
- ParameterType
- Flag
- set
- indexIsCommonType
- isList
- typeNameIndexOrCommonType
- Parameter
- Function
- Flags
- lineAndStatementNumberOffset
- labelInfosOffset
- formalsTable
- localsTable
- lineAndStatementNumberTable
- formalsBegin
- formalsEnd
- labelInfoTable
- code
- calculateSize
- align
- Method
- Type
- Class
- methodTable
- calculateSize
- align
- TemplateObject
- calculateSize
- align
- stringTable
- stringIndexAt
- rawStringIndexAt
- ExportEntry
- ImportEntry
- TranslationData
- Binding
- Type
- Flag
- clearFlags
- setFlag
- hasFlag
- flags
- setType
- type
- hasSignalHandlerBindingFlag
- isValueBinding
- isValueBindingNoAlias
- isValueBindingToAlias
- isSignalHandler
- isAttachedProperty
- isGroupProperty
- isFunctionExpression
- escapedString
- isTranslationBinding
- evaluatesToString
- isNumberBinding
- valueAsBoolean
- InlineComponent
- EnumValue
- Enum
- enumValueAt
- calculateSize
- enumValuesBegin
- enumValuesEnd
- enumValueCount
- Signal
- parameterAt
- calculateSize
- parametersBegin
- parametersEnd
- parameterCount
- Property
- setCommonType
- commonType
- setTypeNameIndex
- typeNameIndex
- isCommonType
- commonTypeOrTypeNameIndex
- isList
- setIsList
- isRequired
- setIsRequired
- isReadOnly
- setIsReadOnly
- RequiredPropertyExtraData
- Alias
- Flag
- hasFlag
- setFlag
- clearFlags
- nameIndex
- setNameIndex
- isObjectAlias
- idIndex
- setIdIndex
- isAliasToLocalAlias
- setIsAliasToLocalAlias
- targetObjectId
- setTargetObjectId
- Object
- Flag
- flags
- hasFlag
- setFlag
- setFlags
- hasAliasAsDefaultProperty
- setHasAliasAsDefaultProperty
- objectId
- setObjectId
- calculateSizeExcludingSignalsAndEnums
- functionOffsetTable
- propertyTable
- aliasTable
- bindingTable
- enumAt
- signalAt
- inlineComponentAt
- namedObjectsInComponentTable
- inlineComponentTable
- requiredPropertyExtraDataAt
- requiredPropertyExtraDataTable
- propertyCount
- aliasCount
- enumCount
- signalCount
- functionCount
- bindingsBegin
- bindingsEnd
- bindingCount
- propertiesBegin
- propertiesEnd
- aliasesBegin
- aliasesEnd
- enumsBegin
- enumsEnd
- signalsBegin
- signalsEnd
- inlineComponentsBegin
- inlineComponentsEnd
- requiredPropertyExtraDataBegin
- requiredPropertyExtraDataEnd
- namedObjectsInComponentCount
- Import
- ImportType
- Import
- QmlUnit
- importAt
- objectAt
- magic_str
- Unit
- qmlUnit
- qmlUnit
- isSingleton
- stringAtInternal
- functionOffsetTable
- classOffsetTable
- templateObjectOffsetTable
- blockOffsetTable
- functionAt
- classAt
- templateObjectAt
- blockAt
- lookupTable
- regexpAt
- constants
- jsClassAt
- translations
- translationContextIndex
- translationContextIndex
- importEntryTable
- localExportEntryTable
- indirectExportEntryTable
- starExportEntryTable
- moduleRequestTable
- TypeReference
- TypeReference
- TypeReferenceMap
- add
- collectFromObject
- collectFromObjects
- InlineComponentData
- InlineComponentData
- InlineComponentData
- CompilationUnit
- CompilationUnit
- IdToObjectMap
- insert
- clear
- contains
- CompilationUnit
- unitData
- setUnitData
- stringAt
- fileName
- finalUrlString
- bindingValueAsString
- bindingValueAsScriptString
- bindingValueAsNumber
- importCount
- importAt
- url
- finalUrl
- resolvedType
- rootPropertyCache
- objectCount
- objectAt
- inlineComponentId
- ListPropertyAssignBehavior
- listPropertyAssignBehavior
- ignoresFunctionSignature
- nativeMethodsAcceptThisObjects
- valueTypesAreCopied
- valueTypesAreAddressable
- valueTypesAreAssertable
- componentsAreBound
- isESModule
- isSharedLibrary
- FunctionIterator
- FunctionIterator
- operator->
- operator++
- operator==
- operator!=
- objectFunctionsBegin
- objectFunctionsEnd
- metaType
- SaveableUnitPointer
- SaveableUnitPointer
- SaveableUnitPointer
- ~SaveableUnitPointer
- saveToDisk
- writeDataToFile
- mutableFlags
- data
Start learning QML with our Intro Training
Find out more