Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4compileddata_p.h
Go to the documentation of this file.
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// Qt-Security score:significant
4#ifndef QV4COMPILEDDATA_P_H
5#define QV4COMPILEDDATA_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 <functional>
19#include <optional>
20
21#include <QtCore/qcryptographichash.h>
22#include <QtCore/qhash.h>
23#include <QtCore/qhashfunctions.h>
24#include <QtCore/qlocale.h>
25#include <QtCore/qscopeguard.h>
26#include <QtCore/qstring.h>
27#include <QtCore/qstringlist.h>
28#include <QtCore/qurl.h>
29#include <QtCore/qvector.h>
30#include <QtCore/qtyperevision.h>
31#include <QtCore/qxpfunctional.h>
32
33#if QT_CONFIG(temporaryfile)
34#include <QtCore/qsavefile.h>
35#endif
36
37#include <private/qendian_p.h>
38#include <private/qqmlnullablevalue_p.h>
39#include <private/qqmlpropertycachevector_p.h>
40#include <private/qqmlrefcount_p.h>
41#include <private/qqmltype_p.h>
42#include <private/qv4compilationunitmapper_p.h>
43#include <private/qv4staticvalue_p.h>
44
45#include <functional>
46#include <limits.h>
47
48QT_BEGIN_NAMESPACE
49
50// Bump this whenever the compiler data structures change in an incompatible way.
51//
52// IMPORTANT:
53//
54// Also change the comment behind the number to describe the latest change. This has the added
55// benefit that if another patch changes the version too, it will result in a merge conflict, and
56// not get removed silently.
57// Also update the comparison functions in qqmlpreviewdiff.cpp when you change the data structures.
58#define QV4_DATA_STRUCTURE_VERSION 0x54 // Stop baking component boundaries and ids
59
60class QIODevice;
61class QQmlTypeNameCache;
62class QQmlType;
63class QQmlEngine;
65class QQmlScriptData;
66
67namespace QQmlPrivate {
69}
70
71namespace QmlIR {
72struct Document;
73}
74
75namespace QV4 {
76namespace Heap {
77struct Module;
78struct String;
79struct InternalClass;
80};
81
82struct Function;
83class EvalISelFactory;
85
86namespace CompiledData {
87
88// index is per-object binding index
90
91// map from name index
93{
94 bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const;
95};
96
97struct String;
98struct Function;
99struct Lookup;
100struct RegExp;
101struct Unit;
102
103template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
105{
106 TableIterator(const Container *container, int index) : container(container), index(index) {}
107 const Container *container;
108 int index;
109
110 const ItemType *operator->() const { return (container->*IndexedGetter)(index); }
111 ItemType operator*() const {return *operator->();}
112
114 {
115 ++index;
116 return *this;
117 }
118
120 {
122 ++index;
123 return result;
124 }
125
126 TableIterator operator+(int offset) const { return TableIterator(container, index + offset); }
127 TableIterator operator-(int offset) const { return TableIterator(container, index - offset); }
128 int operator-(TableIterator other) const { return index - other.index; }
129
130 bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
131 bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
132};
133
135{
137 Location(quint32 l, quint32 c) : Location()
138 {
139 m_data.set<LineField>(l);
140 m_data.set<ColumnField>(c);
141 Q_ASSERT(m_data.get<LineField>() == l);
142 Q_ASSERT(m_data.get<ColumnField>() == c);
143 }
144
145 inline bool operator<(const Location &other) const {
146 return m_data.get<LineField>() < other.m_data.get<LineField>()
147 || (m_data.get<LineField>() == other.m_data.get<LineField>()
148 && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
149 }
150
151 friend size_t qHash(const Location &location, size_t seed = 0)
152 {
153 return QT_PREPEND_NAMESPACE(qHash)(location.m_data.data(), seed);
154 }
155
156 friend bool comparesEqual(const Location &a, const Location &b) noexcept
157 {
158 return a.m_data.data()== b.m_data.data();
159 }
161
162 void set(quint32 line, quint32 column)
163 {
164 m_data.set<LineField>(line);
165 m_data.set<ColumnField>(column);
166 }
167
168 quint32 line() const { return m_data.get<LineField>(); }
169 quint32 column() const { return m_data.get<ColumnField>(); }
170
171private:
174
175 quint32_le_bitfield_union<LineField, ColumnField> m_data;
176};
177static_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");
178
179struct RegExp
180{
189
191
193 RegExp(quint32 flags, quint32 stringIndex) : RegExp()
194 {
195 m_data.set<FlagsField>(flags);
196 m_data.set<StringIndexField>(stringIndex);
197 }
198
199 quint32 flags() const { return m_data.get<FlagsField>(); }
200 quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
201
202private:
205 quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
206};
207static_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");
208
209struct Lookup
210{
217
218 enum Mode : unsigned int {
221 };
222
223 quint32 type() const { return m_data.get<TypeField>(); }
224 quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
225 quint32 mode() const { return m_data.get<ModeField>(); }
226
228 Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup()
229 {
230 m_data.set<TypeField>(type);
231 m_data.set<ModeField>(mode);
232 m_data.set<NameIndexField>(nameIndex);
233 }
234
235private:
238 // 1 bit left
240 quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data;
241};
242static_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");
243
245{
247
248 void set(quint32 nameOffset, bool isAccessor)
249 {
250 m_data.set<NameOffsetField>(nameOffset);
251 m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
252 }
253
254 quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
255 bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
256
257private:
260 quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
261};
262static_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");
263
265{
267 // JSClassMember[nMembers]
268
269 static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
270};
271static_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");
272
273struct String
274{
276
277 static int calculateSize(const QString &str) {
278 // we cannot enconuter strings larger than INT_MAX anyway, as such a string
279 // would already break in other parts of the compilation process
280 return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7;
281 }
282};
283
284static_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");
285
288 qint32_le line; // signed because debug instructions get negative line numbers
290};
291static_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");
292
293struct Block
294{
299
300 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
301
302 static int calculateSize(int nLocals) {
303 int trailingData = nLocals*sizeof (quint32);
304 size_t size = align(align(sizeof(Block)) + size_t(trailingData));
305 Q_ASSERT(size < INT_MAX);
306 return int(size);
307 }
308
309 static size_t align(size_t a) {
310 return (a + 7) & ~size_t(7);
311 }
312};
313static_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");
314
315enum class NamedBuiltin: unsigned int {
317};
318
319enum class CommonType : unsigned int {
320 // Actual named builtins
330
331 // Optimization for very common other types
333
334 // No type specified or not recognized
336};
337
339{
340 enum Flag {
341 NoFlag = 0x0,
342 Common = 0x1,
343 List = 0x2,
344 };
346
347 void set(Flags flags, quint32 typeNameIndexOrCommonType)
348 {
349 m_data.set<IsListField>(flags.testFlag(List) ? 1 : 0);
350 m_data.set<IndexIsCommonTypeField>(flags.testFlag(Common) ? 1 : 0);
351 m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType);
352 }
353
354 bool indexIsCommonType() const
355 {
356 return m_data.get<IndexIsCommonTypeField>() != 0;
357 }
358
359 bool isList() const
360 {
361 return m_data.get<IsListField>() != 0;
362 }
363
365 {
366 return m_data.get<TypeNameIndexOrCommonTypeField>();
367 }
368
369private:
373 quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data;
374};
375static_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");
376
382static_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");
383
384// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
385// for unaligned access. The ordering of the fields is also from largest to smallest.
387{
388 enum Flags : unsigned int {
389 IsStrict = 0x1,
393 };
394
395 // Absolute offset into file where the code for this function is located.
398
402 quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
407 size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
408 quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
409
413
417
419 {
420 return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement);
421 }
422
423 // Keep all unaligned data at the end
426
427 // quint32 formalsIndex[nFormals]
428 // quint32 localsIndex[nLocals]
429
430 const Parameter *formalsTable() const
431 {
432 return reinterpret_cast<const Parameter *>(
433 reinterpret_cast<const char *>(this) + formalsOffset);
434 }
435 const quint32_le *localsTable() const
436 {
437 return reinterpret_cast<const quint32_le *>(
438 reinterpret_cast<const char *>(this) + localsOffset);
439 }
441 {
442 return reinterpret_cast<const CodeOffsetToLineAndStatement *>(
443 reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset());
444 }
445
446 // --- QQmlPropertyCacheCreator interface
447 const Parameter *formalsBegin() const { return formalsTable(); }
448 const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
449 // ---
450
451 const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
452
453 const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
454
455 static int calculateSize(
456 int nFormals, int nLocals, int nLinesAndStatements, int labelInfoSize, int codeSize)
457 {
458 const size_t trailingData = nFormals * sizeof(Parameter)
459 + (nLocals + labelInfoSize) * sizeof (quint32)
460 + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement);
461 size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
462 Q_ASSERT(size < INT_MAX);
463 return int(size);
464 }
465
466 static size_t align(size_t a) {
467 return (a + 7) & ~size_t(7);
468 }
469};
470static_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");
471
483static_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");
484
485struct Class
486{
493
494 const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
495
496 static int calculateSize(int nStaticMethods, int nMethods) {
497 int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
498 size_t size = align(sizeof(Class) + trailingData);
499 Q_ASSERT(size < INT_MAX);
500 return int(size);
501 }
502
503 static size_t align(size_t a) {
504 return (a + 7) & ~size_t(7);
505 }
506};
507static_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");
508
510{
512
513 static int calculateSize(int size) {
514 int trailingData = 2 * size * sizeof(quint32_le);
515 size_t s = align(sizeof(TemplateObject) + trailingData);
516 Q_ASSERT(s < INT_MAX);
517 return int(s);
518 }
519
520 static size_t align(size_t a) {
521 return (a + 7) & ~size_t(7);
522 }
523
524 const quint32_le *stringTable() const {
525 return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
526 }
527
528 uint stringIndexAt(uint i) const {
529 return stringTable()[i];
530 }
531 uint rawStringIndexAt(uint i) const {
532 return stringTable()[size + i];
533 }
534};
535static_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");
536
545static_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");
546
554static_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");
555
556// Qml data structures
557
566static_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");
567
569{
571
585
593
597
598 void clearFlags() { flagsAndType.set<FlagsField>(0); }
599 void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
600 bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
601 Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
602
603 void setType(Type type) { flagsAndType.set<TypeField>(type); }
604 Type type() const { return Type(flagsAndType.get<TypeField>()); }
605
606 union {
607 bool b;
608 quint32_le constantValueIndex;
609 quint32_le compiledScriptIndex; // used when Type_Script
610 quint32_le objectIndex;
611 quint32_le translationDataIndex; // used when Type_Translation
612 quint32 nullMarker;
613 } value;
614 quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
615
618
621
623
624 //reverse of Lexer::singleEscape()
625 static QString escapedString(const QString &string)
626 {
627 QString tmp = QLatin1String("\"");
628 for (int i = 0; i < string.size(); ++i) {
629 const QChar &c = string.at(i);
630 switch (c.unicode()) {
631 case 0x08:
632 tmp += QLatin1String("\\b");
633 break;
634 case 0x09:
635 tmp += QLatin1String("\\t");
636 break;
637 case 0x0A:
638 tmp += QLatin1String("\\n");
639 break;
640 case 0x0B:
641 tmp += QLatin1String("\\v");
642 break;
643 case 0x0C:
644 tmp += QLatin1String("\\f");
645 break;
646 case 0x0D:
647 tmp += QLatin1String("\\r");
648 break;
649 case 0x22:
650 tmp += QLatin1String("\\\"");
651 break;
652 case 0x27:
653 tmp += QLatin1String("\\\'");
654 break;
655 case 0x5C:
656 tmp += QLatin1String("\\\\");
657 break;
658 default:
659 tmp += c;
660 break;
661 }
662 }
663 tmp += QLatin1Char('\"');
664 return tmp;
665 }
666
668 {
669 const Binding::Type bindingType = type();
670 return bindingType == Type_Translation || bindingType == Type_TranslationById;
671 }
673
674 bool isNumberBinding() const { return type() == Type_Number; }
675
676 bool valueAsBoolean() const
677 {
678 if (type() == Type_Boolean)
679 return value.b;
680 return false;
681 }
682};
683
684static_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");
685
692
693static_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");
694
700static_assert(sizeof(EnumValue) == 8, "EnumValue structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
701
702struct Enum
703{
707
708 const EnumValue *enumValueAt(int idx) const {
709 return reinterpret_cast<const EnumValue*>(this + 1) + idx;
710 }
711
712 static int calculateSize(int nEnumValues) {
713 return (sizeof(Enum)
714 + nEnumValues * sizeof(EnumValue)
715 + 7) & ~0x7;
716 }
717
718 // --- QQmlPropertyCacheCreatorInterface
719 const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
720 const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
721 int enumValueCount() const { return nEnumValues; }
722 // ---
723};
724static_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");
725
726struct Signal
727{
731 // Parameter parameters[1];
732
733 const Parameter *parameterAt(int idx) const {
734 return reinterpret_cast<const Parameter*>(this + 1) + idx;
735 }
736
737 static int calculateSize(int nParameters) {
738 return (sizeof(Signal)
739 + nParameters * sizeof(Parameter)
740 + 7) & ~0x7;
741 }
742
743 // --- QQmlPropertyCacheCceatorInterface
744 const Parameter *parametersBegin() const { return parameterAt(0); }
745 const Parameter *parametersEnd() const { return parameterAt(nParameters); }
746 int parameterCount() const { return nParameters; }
747 // ---
748};
749static_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");
750
751/*
752 * We aim to minimize the size of a struct as much as possible, while preserving at least 28 bits
753 * for each index.
754 *
755 * Note that Name and Type indices are provided by StringTableGenerator, containing a hashmap
756 * (and a list) of unique strings within one Compilation Unit. It sounds rather unrealistic to have
757 * 2^28 (260+ million) unique strings within 1 CU (even if it's some form of global registry), not
758 * to mention the amount of memory needed to maintain such a StringTableGenerator.
759 * Therefore, after some preliminary analysis, it seems that even 20 bits
760 * should be a rather conservative cap.
761 *
762 * However it doesn't seem to easily provide many benefits atm other than better (logically) grouped
763 * unions like, let's say nameIndexAndAttributes.
764 *
765 * Atm 32-bit member nameIndexAndVirtSpecifiers looks smth like this:
766 *
767 * NameIndexField IsVirtualField IsOverrideField IsFinalField
768 * |10100000101000111000001110000| 0 | 1 | 0 |
769 *
770 */
772{
773private:
778
784
785public:
795
796 quint32 nameIndex() const { return nameIndexAndVirtSpecifiers.get<NameIndexField>(); }
797 void setNameIndex(int nameIndex) { nameIndexAndVirtSpecifiers.set<NameIndexField>(nameIndex); }
798
799 bool isVirtual() const { return nameIndexAndVirtSpecifiers.get<IsVirtualField>(); }
800 void setIsVirtual(bool isVirtual)
801 {
802 nameIndexAndVirtSpecifiers.set<IsVirtualField>(isVirtual ? 1 : 0);
803 }
804
805 bool isOverride() const { return nameIndexAndVirtSpecifiers.get<IsOverrideField>(); }
806 void setIsOverride(bool isOverride)
807 {
808 nameIndexAndVirtSpecifiers.set<IsOverrideField>(isOverride ? 1 : 0);
809 }
810
811 bool isFinal() const { return nameIndexAndVirtSpecifiers.get<IsFinalField>(); }
812 void setIsFinal(bool isFinal) { nameIndexAndVirtSpecifiers.set<IsFinalField>(isFinal ? 1 : 0); }
813
815 {
816 data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t));
817 data.set<IsCommonTypeField>(true);
818 }
819
821 if (isCommonType())
822 return CommonType(data.get<CommonTypeOrTypeNameIndexField>());
823 return CommonType::Invalid;
824 }
825
826 void setTypeNameIndex(int nameIndex)
827 {
828 data.set<CommonTypeOrTypeNameIndexField>(nameIndex);
829 data.set<IsCommonTypeField>(false);
830 }
831
832 int typeNameIndex() const
833 {
834 return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>();
835 }
836
837 bool isCommonType() const { return data.get<IsCommonTypeField>(); }
838 uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); }
839
840 bool isList() const { return data.get<IsListField>(); }
841 void setIsList(bool isList) { data.set<IsListField>(isList); }
842
843 bool isRequired() const { return data.get<IsRequiredField>(); }
844 void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
845
846 bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
847 void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
848};
849static_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");
850
854
855static_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");
856
857struct Alias
858{
859 bool isReadOnly() const { return m_nameIndexAndFlags.get<IsReadOnlyField>(); }
860 void setIsReadOnly(bool isReadOnly) { m_nameIndexAndFlags.set<IsReadOnlyField>(isReadOnly); }
861
862 quint32 nameIndex() const { return m_nameIndexAndFlags.get<NameIndexField>(); }
863 void setNameIndex(quint32 nameIndex)
864 {
865 m_nameIndexAndFlags.set<NameIndexField>(nameIndex);
866 }
867
868 quint32 idIndex() const { return m_idIndexField; }
869 void setIdIndex(quint32 idIndex) { m_idIndexField = idIndex; }
870
871 quint32 propertyNameIndex() const { return m_propertyNameIndex; }
872 void setPropertyNameIndex(quint32 propertyNameIndex)
873 {
874 m_propertyNameIndex = propertyNameIndex;
875 }
876
877 Location location() const { return m_location; }
878 void setLocation(Location location) { m_location = location; }
879
880 Location referenceLocation() const { return m_referenceLocation; }
881 void setReferenceLocation(Location referenceLocation)
882 {
883 m_referenceLocation = referenceLocation;
884 }
885
886private:
889
890 quint32_le_bitfield_union<NameIndexField, IsReadOnlyField> m_nameIndexAndFlags;
891 quint32_le m_idIndexField;
892 quint32_le m_propertyNameIndex; // string index
893 Location m_location;
894 Location m_referenceLocation;
895};
896static_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");
897
898struct Object
899{
900private:
903 // 16 bits vacant
904public:
905 enum Flag : unsigned int {
906 NoFlag = 0x0,
909 };
911
912 // Depending on the use, this may be the type name to instantiate before instantiating this
913 // object. For grouped properties the type name will be empty and for attached properties
914 // it will be the name of the attached type.
919 qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
927 quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
928 quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
938// Function[]
939// Property[]
940// Signal[]
941// Binding[]
942// InlineComponent[]
943// RequiredPropertyExtraData[]
944
945 Flags flags() const
946 {
947 return Flags(flagsAndDefaultPropertyIsAlias.get<FlagsField>());
948 }
949
950 bool hasFlag(Flag flag) const
951 {
952 return flagsAndDefaultPropertyIsAlias.get<FlagsField>() & flag;
953 }
954
955 void setFlag(Flag flag)
956 {
957 flagsAndDefaultPropertyIsAlias.set<FlagsField>(
958 flagsAndDefaultPropertyIsAlias.get<FlagsField>() | flag);
959 }
960
961 void setFlags(Flags flags)
962 {
963 flagsAndDefaultPropertyIsAlias.set<FlagsField>(flags);
964 }
965
967 {
968 return flagsAndDefaultPropertyIsAlias.get<DefaultPropertyIsAliasField>();
969 }
970
971 void setHasAliasAsDefaultProperty(bool defaultAlias)
972 {
973 flagsAndDefaultPropertyIsAlias.set<DefaultPropertyIsAliasField>(defaultAlias);
974 }
975
976 static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nInlineComponents, int nRequiredPropertyExtraData)
977 {
978 return ( sizeof(Object)
979 + nFunctions * sizeof(quint32)
980 + nProperties * sizeof(Property)
981 + nAliases * sizeof(Alias)
982 + nEnums * sizeof(quint32)
983 + nSignals * sizeof(quint32)
984 + nBindings * sizeof(Binding)
985 + nInlineComponents * sizeof(InlineComponent)
986 + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
987 + 0x7
988 ) & ~0x7;
989 }
990
992 {
993 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
994 }
995
996 const Property *propertyTable() const
997 {
998 return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
999 }
1000
1001 const Alias *aliasTable() const
1002 {
1003 return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
1004 }
1005
1006 const Binding *bindingTable() const
1007 {
1008 return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
1009 }
1010
1011 const Enum *enumAt(int idx) const
1012 {
1013 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
1014 const quint32_le offset = offsetTable[idx];
1015 return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
1016 }
1017
1018 const Signal *signalAt(int idx) const
1019 {
1020 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
1021 const quint32_le offset = offsetTable[idx];
1022 return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
1023 }
1024
1026 {
1027 return inlineComponentTable() + idx;
1028 }
1029
1031 {
1032 return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
1033 }
1034
1039
1041 {
1042 return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
1043 }
1044
1045 // --- QQmlPropertyCacheCreator interface
1046 int propertyCount() const { return nProperties; }
1047 int aliasCount() const { return nAliases; }
1048 int enumCount() const { return nEnums; }
1049 int signalCount() const { return nSignals; }
1050 int functionCount() const { return nFunctions; }
1051 int inlineComponentCount() const { return nInlineComponents; }
1052
1053 const Binding *bindingsBegin() const { return bindingTable(); }
1054 const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
1055 int bindingCount() const { return nBindings; }
1056
1057 const Property *propertiesBegin() const { return propertyTable(); }
1058 const Property *propertiesEnd() const { return propertyTable() + nProperties; }
1059
1060 const Alias *aliasesBegin() const { return aliasTable(); }
1061 const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
1062
1064 EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
1065 EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
1066
1068 SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
1069 SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
1070
1072 InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
1073 InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
1074
1076 RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); }
1077 RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }
1078};
1079static_assert(sizeof(Object) == 76, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
1080
1082{
1083 enum ImportType : unsigned int {
1088 };
1090
1093
1097
1099 {
1100 type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0;
1101 }
1102};
1103static_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");
1104
1106{
1111
1112 const Import *importAt(int idx) const {
1113 return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
1114 }
1115
1116 const Object *objectAt(int idx) const {
1117 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
1118 const quint32_le offset = offsetTable[idx];
1119 return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
1120 }
1121};
1122static_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");
1123
1124static const char magic_str[] = "qv4cdata";
1125
1126struct Unit
1127{
1128 // DO NOT CHANGE THESE FIELDS EVER
1129 char magic[8];
1131 // END DO NOT CHANGE THESE FIELDS EVER
1132
1133 quint32_le reserved; // For predictable alignment and size. Used to be Qt version.
1134
1135 // A sourceTimeStamp of -1 marks a unit that is validated by source content hashing rather
1136 // than by time stamp. In that case sourceChecksum holds the checksum of the source code and
1137 // is compared against the freshly computed checksum of the source on load. This is used for
1138 // cache files generated at run time, where the source's time stamp may be unreliable (e.g.
1139 // reproducible builds that pin mtimes via SOURCE_DATE_EPOCH). Units generated by qmlcachegen
1140 // at compile time keep their actual time stamp and leave sourceChecksum zeroed.
1142 quint32_le unitSize; // Size of the Unit and any depending data.
1143
1144 // Kept before md5Checksum, and therefore outside its coverage, so that it can be patched in
1145 // when saving a unit to disk without invalidating md5Checksum.
1147
1148 char md5Checksum[16]; // checksum of all bytes following this field.
1150
1151 enum : unsigned int {
1153 StaticData = 0x2, // Unit data persistent in memory?
1155 IsSharedLibrary = 0x8, // .pragma shared?
1157 PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation
1158 IsStrict = 0x40,
1169 };
1204
1206
1207 /* QML specific fields */
1208
1209 const QmlUnit *qmlUnit() const {
1210 return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
1211 }
1212
1214 return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
1215 }
1216
1217 bool isSingleton() const {
1218 return flags & Unit::IsSingleton;
1219 }
1220
1222 // ListPropertyAssignReplace is the combination of both replace bits, so it must be tested
1223 // for an exact match.
1224 return (flags & Unit::ListPropertyAssignReplace) == Unit::ListPropertyAssignReplace;
1225 }
1226
1228 return flags & Unit::ListPropertyAssignReplaceIfNotDefault;
1229 }
1230 /* end QML specific fields*/
1231
1232 QString stringAtInternal(uint idx) const {
1233 Q_ASSERT(idx < stringTableSize);
1234 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
1235 const quint32_le offset = offsetTable[idx];
1236 const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
1237 Q_ASSERT(str->size >= 0);
1238#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1239 const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
1240 if (flags & StaticData)
1241 return QString::fromRawData(characters, str->size);
1242 return QString(characters, str->size);
1243#else
1244 const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
1245 QString qstr(str->size, Qt::Uninitialized);
1246 QChar *ch = qstr.data();
1247 for (int i = 0; i < str->size; ++i)
1248 ch[i] = QChar(quint16(characters[i]));
1249 return qstr;
1250#endif
1251 }
1252
1253 const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
1254 const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
1255 const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
1256 const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
1257
1258 const Function *functionAt(int idx) const {
1259 const quint32_le *offsetTable = functionOffsetTable();
1260 const quint32_le offset = offsetTable[idx];
1261 return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
1262 }
1263
1264 const Class *classAt(int idx) const {
1265 const quint32_le *offsetTable = classOffsetTable();
1266 const quint32_le offset = offsetTable[idx];
1267 return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
1268 }
1269
1270 const TemplateObject *templateObjectAt(int idx) const {
1271 const quint32_le *offsetTable = templateObjectOffsetTable();
1272 const quint32_le offset = offsetTable[idx];
1273 return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
1274 }
1275
1276 const Block *blockAt(int idx) const {
1277 const quint32_le *offsetTable = blockOffsetTable();
1278 const quint32_le offset = offsetTable[idx];
1279 return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
1280 }
1281
1282 const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
1283 const RegExp *regexpAt(int index) const {
1284 return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
1285 }
1286 const quint64_le *constants() const {
1287 return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
1288 }
1289
1290 const JSClassMember *jsClassAt(int idx, int *nMembers) const {
1291 const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
1292 const quint32_le offset = offsetTable[idx];
1293 const char *ptr = reinterpret_cast<const char *>(this) + offset;
1294 const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
1295 *nMembers = klass->nMembers;
1296 return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
1297 }
1298
1300 return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
1301 }
1302
1304 if ( translationTableSize == 0)
1305 return nullptr;
1306 return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this))
1307 + offsetToTranslationTable
1308 + translationTableSize * sizeof(CompiledData::TranslationData)); }
1309
1311 if ( translationTableSize == 0)
1312 return nullptr;
1313 return reinterpret_cast<quint32_le*>((reinterpret_cast<char *>(this))
1314 + offsetToTranslationTable
1315 + translationTableSize * sizeof(CompiledData::TranslationData)); }
1316
1317 const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
1318 const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
1319 const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
1320 const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
1321
1322 const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
1323
1324 bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
1325};
1326
1327static_assert(sizeof(Unit) == 216, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
1328
1329// The runtime data holds what we can only calculate once the types a unit refers to are resolved.
1330// It is stored separately from the unit, in tables parallel to the unit's objects and bindings.
1346
1348
1350{
1357
1363
1365 {
1366 return reinterpret_cast<const RuntimeBinding *>(
1367 reinterpret_cast<const char *>(this) + sizeof(RuntimeObject));
1368 }
1369
1371 {
1372 return reinterpret_cast<RuntimeBinding *>(
1373 reinterpret_cast<char *>(this) + sizeof(RuntimeObject));
1374 }
1375
1377 {
1378 return reinterpret_cast<const RuntimeBindingIndex *>(
1379 reinterpret_cast<const char *>(this) + offsetToBindingOrder);
1380 }
1381
1383 {
1384 return reinterpret_cast<RuntimeBindingIndex *>(
1385 reinterpret_cast<char *>(this) + offsetToBindingOrder);
1386 }
1387
1389 {
1390 return reinterpret_cast<const quint32_le *>(
1391 reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
1392 }
1393
1395 {
1396 return reinterpret_cast<quint32_le *>(
1397 reinterpret_cast<char *>(this) + offsetToNamedObjectsInComponent);
1398 }
1399};
1400
1402{
1404
1405 const RuntimeObject *objectAt(int idx) const
1406 {
1407 const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(
1408 reinterpret_cast<const char *>(this) + sizeof(RuntimeDataBlock));
1409 return reinterpret_cast<const RuntimeObject *>(
1410 reinterpret_cast<const char *>(this) + offsetTable[idx]);
1411 }
1412
1414 {
1415 const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(
1416 reinterpret_cast<const char *>(this) + sizeof(RuntimeDataBlock));
1417 return reinterpret_cast<RuntimeObject *>(
1418 reinterpret_cast<char *>(this) + offsetTable[idx]);
1419 }
1420};
1421
1423{
1425 : location(loc)
1426 , needsCreation(false)
1427 , errorWhenNotFound(false)
1428 {}
1429 Location location; // first use
1430 bool needsCreation : 1; // whether the type needs to be creatable or not
1432};
1433
1434// Map from name index to location of first use.
1436{
1437 TypeReference &add(int nameIndex, const Location &loc) {
1438 Iterator it = find(nameIndex);
1439 if (it != end())
1440 return *it;
1441 return *insert(nameIndex, loc);
1442 }
1443
1444 template <typename CompiledObject>
1445 void collectFromObject(const CompiledObject *obj)
1446 {
1447 if (obj->inheritedTypeNameIndex != 0) {
1448 TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
1449 r.needsCreation = true;
1450 r.errorWhenNotFound = true;
1451 }
1452
1453 auto binding = obj->bindingsBegin();
1454 auto const bindingEnd = obj->bindingsEnd();
1455 for ( ; binding != bindingEnd; ++binding) {
1457 this->add(binding->propertyNameIndex, binding->location);
1458 }
1459
1460 auto ic = obj->inlineComponentsBegin();
1461 auto const icEnd = obj->inlineComponentsEnd();
1462 for (; ic != icEnd; ++ic) {
1463 this->add(ic->nameIndex, ic->location);
1464 }
1465 }
1466
1467 template <typename Iterator>
1468 void collectFromObjects(Iterator it, Iterator end)
1469 {
1470 for (; it != end; ++it)
1471 collectFromObject(*it);
1472 }
1473};
1474
1476
1478
1480 InlineComponentData(const QQmlType &qmlType, int objectIndex, int nameIndex)
1481 : qmlType(qmlType)
1482 , objectIndex(objectIndex)
1483 , nameIndex(nameIndex)
1484 {}
1485
1486 QQmlType qmlType;
1487 int objectIndex = -1;
1488 int nameIndex = -1;
1489};
1490
1492{
1494
1495 const Unit *data = nullptr;
1496 const QmlUnit *qmlData = nullptr;
1499
1503
1504 // pointers either to data->constants() or little-endian memory copy.
1505 const StaticValue *constants = nullptr;
1506
1508
1510
1511 // index is object index. This allows fast access to the
1512 // property data when initializing bindings, avoiding expensive
1513 // lookups by string (property name).
1515
1518
1520
1521 QQmlType qmlType;
1522
1524
1525public:
1526 // --- interface for QQmlPropertyCacheCreator
1530
1531 using IdToObjectMap = QMap<int, int>;
1532
1533 explicit CompilationUnit(const Unit *unitData,
1534 const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions,
1535 LookupValidationFn validateLookupSignatures,
1536 const QString &fileName = QString(),
1537 const QString &finalUrlString = QString())
1538 : CompilationUnit(unitData, fileName, finalUrlString)
1539 {
1540 this->aotCompiledFunctions = aotCompiledFunctions;
1541 this->validateLookupSignatures = validateLookupSignatures;
1542 }
1543
1545 const Unit *unitData = nullptr, const QString &fileName = QString(),
1546 const QString &finalUrlString = QString());
1547
1549
1550 const Unit *unitData() const { return data; }
1551
1552 void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
1553 const QString &fileName = QString(), const QString &finalUrlString = QString())
1554 {
1555 data = unitData;
1556 qmlData = nullptr;
1557#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1558 delete [] constants;
1559#endif
1560 constants = nullptr;
1561 m_fileName.clear();
1562 m_finalUrlString.clear();
1563 if (!data)
1564 return;
1565
1566 qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
1567
1568#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1569 StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
1570 const quint64_le *littleEndianConstants = data->constants();
1571 for (uint i = 0; i < data->constantTableSize; ++i)
1572 bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
1573 constants = bigEndianConstants;
1574#else
1575 constants = reinterpret_cast<const StaticValue*>(data->constants());
1576#endif
1577
1578 m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
1579 m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
1580 }
1581
1582 QString stringAt(uint index) const
1583 {
1584 if (index < data->stringTableSize)
1585 return data->stringAtInternal(index);
1586
1587 const qsizetype dynamicIndex = index - data->stringTableSize;
1588 Q_ASSERT(dynamicIndex < dynamicStrings.size());
1589 return dynamicStrings.at(dynamicIndex);
1590 }
1591
1592 QString fileName() const { return m_fileName; }
1593 QString finalUrlString() const { return m_finalUrlString; }
1594
1596 {
1597 using namespace CompiledData;
1598 switch (binding->type()) {
1599 case Binding::Type_Script:
1600 case Binding::Type_String:
1601 return stringAt(binding->stringIndex);
1602 case Binding::Type_Null:
1603 return QStringLiteral("null");
1605 return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
1606 case Binding::Type_Number:
1607 return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
1609 return QString();
1610 case Binding::Type_TranslationById:
1611 case Binding::Type_Translation:
1612 return stringAt(data->translations()[binding->value.translationDataIndex].stringIndex);
1613 default:
1614 break;
1615 }
1616 return QString();
1617 }
1618
1620 {
1622 ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
1623 : bindingValueAsString(binding);
1624 }
1625
1626 double bindingValueAsNumber(const CompiledData::Binding *binding) const
1627 {
1629 return 0.0;
1630 return constants[binding->value.constantValueIndex].doubleValue();
1631 }
1632
1633 Q_QML_EXPORT static QString localCacheFilePath(const QUrl &url);
1634
1635 // sourceChecksum is invoked to obtain the checksum of the current source code. It is only
1636 // called when the cached unit is in content-hash mode (sourceTimeStamp == -1), so units
1637 // validated by time stamp never pay the cost of reading and hashing the source.
1639 const QUrl &url, const QDateTime &sourceTimeStamp,
1641
1642 // saveToDisk always stores the unit in content-hash mode: it sets sourceTimeStamp to -1 and
1643 // writes the result of sourceChecksum() into the unit. It is used for cache files generated
1644 // at run time.
1646 const QUrl &unitUrl, qxp::function_ref<QByteArray() const> sourceChecksum,
1647 QString *errorString) const;
1648
1649 int importCount() const { return qmlData->nImports; }
1650 const CompiledData::Import *importAt(int index) const { return qmlData->importAt(index); }
1651
1652 Q_QML_EXPORT QStringList moduleRequests() const;
1653
1654 // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
1655 // warnings about that code. They include any potential URL interceptions and thus represent the
1656 // "physical" location of the code.
1657 //
1658 // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
1659 // They are _not_ intercepted and thus represent the "logical" name for the code.
1660
1661 QUrl url() const
1662 {
1663 if (!m_url.isValid())
1664 m_url = QUrl(fileName());
1665 return m_url;
1666 }
1667
1669 {
1670 if (!m_finalUrl.isValid())
1671 m_finalUrl = QUrl(finalUrlString());
1672 return m_finalUrl;
1673 }
1674
1675 ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
1676 ResolvedTypeReference *resolvedType(QMetaType type) const;
1677
1679 {
1680 return propertyCaches.isEmpty()
1681 ? QQmlPropertyCache::ConstPtr()
1682 : propertyCaches.at(/*root object*/0);
1683 }
1684
1685 int objectCount() const { return qmlData->nObjects; }
1686
1687 // Resolves implicit component wrapper indices (>= objectCount()) to the
1688 // wrapped child object index. Returns the index unchanged for real objects.
1689 int resolvedIndex(int index) const
1690 {
1691 if (index < objectCount())
1692 return index;
1693 const QQmlPropertyData *p = propertyCaches.at(index)->defaultProperty();
1694 Q_ASSERT(p && p->isComponentWrapper());
1695 return p->wrappedObjectIndex();
1696 }
1697
1698 const CompiledObject *objectAt(int index) const
1699 {
1701 }
1702
1703 const RuntimeObject *runtimeObjectAt(int index) const
1704 {
1705 Q_ASSERT(runtimeData);
1707 }
1708
1709 bool objectHasDeferredBindings(int objectIndex) const
1710 {
1711 return runtimeObjectAt(objectIndex)->flags & RuntimeObject::HasDeferredBindings;
1712 }
1713
1714 bool objectHasCustomParserBindings(int objectIndex) const
1715 {
1717 }
1718
1719 bool objectIsPopulatedByDeferredBinding(int objectIndex) const
1720 {
1722 }
1723
1724 bool objectIsComponent(int objectIndex) const
1725 {
1726 return runtimeObjectAt(objectIndex)->flags & RuntimeObject::IsComponent;
1727 }
1728
1729 int objectId(int objectIndex) const { return runtimeObjectAt(objectIndex)->objectId; }
1730
1732 {
1733 return runtimeObjectAt(objectIndex)->nNamedObjectsInComponent;
1734 }
1735
1736 bool bindingIsDeferred(int objectIndex, int bindingIndex) const
1737 {
1738 return runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex].flags
1740 }
1741
1742 bool bindingIsCustomParser(int objectIndex, int bindingIndex) const
1743 {
1744 return runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex].flags
1746 }
1747
1748 bool bindingIsSignalHandlerExpression(int objectIndex, int bindingIndex) const
1749 {
1750 return runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex].flags
1752 }
1753
1754 bool bindingIsSignalHandlerObject(int objectIndex, int bindingIndex) const
1755 {
1756 return runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex].flags
1758 }
1759
1760 bool bindingIsPropertyObserver(int objectIndex, int bindingIndex) const
1761 {
1762 return runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex].flags
1764 }
1765
1766 bool bindingIsSignalHandler(int objectIndex, int bindingIndex) const
1767 {
1768 return runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex].flags
1771 }
1772
1773 std::optional<int> bindingFoldedEnum(int objectIndex, int bindingIndex) const
1774 {
1775 const RuntimeBinding &binding = runtimeObjectAt(objectIndex)->bindingTable()[bindingIndex];
1776 if (binding.flags & RuntimeBinding::IsFoldedEnum)
1777 return int(binding.enumValue);
1778 return std::nullopt;
1779 }
1780
1781 const RuntimeBindingIndex *bindingApplicationOrder(int objectIndex) const
1782 {
1783 return runtimeObjectAt(objectIndex)->bindingOrder();
1784 }
1785
1786 void allocateRuntimeData();
1787 quint32_le *allocateNamedObjectsInComponent(int objectIndex, quint32 count);
1788
1790 {
1791 return reinterpret_cast<RuntimeDataBlock *>(runtimeDataStorage.data());
1792 }
1793
1794 // Returns the index of the implicit component wrapper, or -1.
1795 // Scans property caches at indices >= objectCount().
1796 int implicitComponentForObject(int index) const
1797 {
1798 for (int i = objectCount(), end = propertyCaches.count(); i < end; ++i) {
1799 const QQmlPropertyData *p = propertyCaches.at(i)->defaultProperty();
1800 Q_ASSERT(p && p->isComponentWrapper());
1801 if (p->wrappedObjectIndex() == index)
1802 return i;
1803 }
1804 return -1;
1805 }
1806
1807 int inlineComponentId(const QString &inlineComponentName) const
1808 {
1809 for (uint i = 0; i < qmlData->nObjects; ++i) {
1810 auto *object = qmlData->objectAt(i);
1811 for (auto it = object->inlineComponentsBegin(), end = object->inlineComponentsEnd();
1812 it != end; ++it) {
1813 if (stringAt(it->nameIndex) == inlineComponentName)
1814 return it->objectIndex;
1815 }
1816 }
1817 return -1;
1818 }
1819
1820 void finalizeCompositeType(const QQmlType &type);
1821
1822 bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
1823
1834
1839
1844
1846 {
1848 }
1849
1854
1856 {
1858 }
1859
1861 {
1863 }
1864
1865 bool isESModule() const
1866 {
1868 }
1869
1870 bool isSharedLibrary() const
1871 {
1873 }
1874
1876 {
1877 FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
1878 : unit(unit), object(object), index(index) {}
1882
1884 {
1885 return unit->functionAt(object->functionOffsetTable()[index]);
1886 }
1887
1888 void operator++() { ++index; }
1889 bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
1890 bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
1891 };
1892
1894 {
1895 return FunctionIterator(unitData(), object, 0);
1896 }
1897
1899 {
1900 return FunctionIterator(unitData(), object, object->nFunctions);
1901 }
1902
1903 QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
1904 QMetaType metaType() const { return qmlType.typeId(); }
1905
1906private:
1907 QString m_fileName; // initialized from data->sourceFileIndex
1908 QString m_finalUrlString; // initialized from data->finalUrlIndex
1909
1910 mutable QQmlNullableValue<QUrl> m_url;
1911 mutable QQmlNullableValue<QUrl> m_finalUrl;
1912};
1913
1915{
1917public:
1923
1925
1926 template<typename Char>
1927 bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
1928 {
1929 const quint32_le oldFlags = mutableFlags();
1930 auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
1931 mutableFlags() |= temporaryFlags;
1932 return writer(data<Char>(), size());
1933 }
1934
1935 static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
1936 QString *errorString)
1937 {
1938#if QT_CONFIG(temporaryfile)
1939 QSaveFile cacheFile(outputFileName);
1940 if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
1941 || cacheFile.write(data, size) != size
1942 || !cacheFile.commit()) {
1943 *errorString = cacheFile.errorString();
1944 return false;
1945 }
1946
1947 errorString->clear();
1948 return true;
1949#else
1950 Q_UNUSED(outputFileName);
1951 *errorString = QStringLiteral("features.temporaryfile is disabled.");
1952 return false;
1953#endif
1954 }
1955
1956private:
1957 const Unit *unit;
1958 quint32 temporaryFlags;
1959
1960 quint32_le &mutableFlags() const
1961 {
1962 return const_cast<Unit *>(unit)->flags;
1963 }
1964
1965 template<typename Char>
1966 const Char *data() const
1967 {
1968 Q_STATIC_ASSERT(sizeof(Char) == 1);
1969 const Char *dataPtr;
1970 memcpy(&dataPtr, &unit, sizeof(dataPtr));
1971 return dataPtr;
1972 }
1973
1974 quint32 size() const
1975 {
1976 return unit->unitSize;
1977 }
1978};
1979
1980
1981} // CompiledData namespace
1982} // QV4 namespace
1983
1986
1987QT_END_NAMESPACE
1988
1989#endif
static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size, QString *errorString)
bool saveToDisk(const std::function< bool(const Char *, quint32)> &writer) const
Combined button and popup list for selecting options.
static const char magic_str[]
Definition qjsvalue.h:24
Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE)
#define QV4_DATA_STRUCTURE_VERSION
Q_DECLARE_OPERATORS_FOR_FLAGS(QV4::CompiledData::ParameterType::Flags)
void setPropertyNameIndex(quint32 propertyNameIndex)
quint32 propertyNameIndex() const
void setIsReadOnly(bool isReadOnly)
void setReferenceLocation(Location referenceLocation)
void setNameIndex(quint32 nameIndex)
Location referenceLocation() const
void setIdIndex(quint32 idIndex)
void setLocation(Location location)
quint32_le_bitfield_union< FlagsField, TypeField > flagsAndType
bool hasFlag(Flag flag) const
static QString escapedString(const QString &string)
const quint32_le * localsTable() const
static size_t align(size_t a)
static int calculateSize(int nLocals)
static int calculateSize(int nStaticMethods, int nMethods)
static size_t align(size_t a)
const Method * methodTable() const
bool operator!=(const FunctionIterator &rhs) const
bool operator==(const FunctionIterator &rhs) const
FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
std::unique_ptr< CompilationUnitMapper > backingFile
QString bindingValueAsScriptString(const CompiledData::Binding *binding) const
QHash< QString, InlineComponentData > inlineComponentData
void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit=nullptr, const QString &fileName=QString(), const QString &finalUrlString=QString())
int inlineComponentId(const QString &inlineComponentName) const
quint32 namedObjectCountInComponent(int objectIndex) const
double bindingValueAsNumber(const CompiledData::Binding *binding) const
std::optional< int > bindingFoldedEnum(int objectIndex, int bindingIndex) const
bool bindingIsDeferred(int objectIndex, int bindingIndex) const
void finalizeCompositeType(const QQmlType &type)
ResolvedTypeReference * resolvedType(int id) const
const CompiledData::Function CompiledFunction
const QQmlPrivate::AOTCompiledFunction * aotCompiledFunctions
quint32_le * allocateNamedObjectsInComponent(int objectIndex, quint32 count)
bool bindingIsSignalHandlerExpression(int objectIndex, int bindingIndex) const
bool bindingIsPropertyObserver(int objectIndex, int bindingIndex) const
int objectId(int objectIndex) const
int implicitComponentForObject(int index) const
bool bindingIsCustomParser(int objectIndex, int bindingIndex) const
bool bindingIsSignalHandlerObject(int objectIndex, int bindingIndex) const
ResolvedTypeReferenceMap resolvedTypes
bool objectHasCustomParserBindings(int objectIndex) const
QList< BindingPropertyData > bindingPropertyDataPerObject
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const
bool objectIsPopulatedByDeferredBinding(int objectIndex) const
QQmlType qmlTypeForComponent(const QString &inlineComponentName=QString()) const
FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
QQmlRefPointer< QQmlTypeNameCache > typeNameCache
Q_QML_EXPORT bool saveToDisk(const QUrl &unitUrl, qxp::function_ref< QByteArray() const > sourceChecksum, QString *errorString) const
const RuntimeObject * runtimeObjectAt(int index) const
FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
ListPropertyAssignBehavior listPropertyAssignBehavior() const
const CompiledObject * objectAt(int index) const
const CompiledData::Object CompiledObject
const CompiledData::Binding CompiledBinding
const CompiledData::Import * importAt(int index) const
bool objectIsComponent(int objectIndex) const
CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions, LookupValidationFn validateLookupSignatures, const QString &fileName=QString(), const QString &finalUrlString=QString())
QList< QQmlRefPointer< QQmlScriptData > > dependentScripts
bool bindingIsSignalHandler(int objectIndex, int bindingIndex) const
QString bindingValueAsString(const CompiledData::Binding *binding) const
Q_QML_EXPORT bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, qxp::function_ref< QByteArray() const > sourceChecksum, QString *errorString)
QQmlPropertyCache::ConstPtr rootPropertyCache() const
bool objectHasDeferredBindings(int objectIndex) const
const RuntimeBindingIndex * bindingApplicationOrder(int objectIndex) const
const EnumValue * enumValueAt(int idx) const
const EnumValue * enumValuesEnd() const
const EnumValue * enumValuesBegin() const
static int calculateSize(int nEnumValues)
const quint32_le * localsTable() const
static size_t align(size_t a)
const CodeOffsetToLineAndStatement * lineAndStatementNumberTable() const
size_t lineAndStatementNumberOffset() const
static int calculateSize(int nFormals, int nLocals, int nLinesAndStatements, int labelInfoSize, int codeSize)
const Parameter * formalsTable() const
const Parameter * formalsEnd() const
const Parameter * formalsBegin() const
const quint32_le * labelInfoTable() const
InlineComponentData(const QQmlType &qmlType, int objectIndex, int nameIndex)
void set(quint32 nameOffset, bool isAccessor)
static int calculateSize(int nMembers)
Location(quint32 l, quint32 c)
void set(quint32 line, quint32 column)
friend size_t qHash(const Location &location, size_t seed=0)
bool operator<(const Location &other) const
friend bool comparesEqual(const Location &a, const Location &b) noexcept
Lookup(Type type, Mode mode, quint32 nameIndex)
TableIterator< Enum, Object, &Object::enumAt > EnumIterator
EnumIterator enumsBegin() const
Q_DECLARE_FLAGS(Flags, Flag)
const RequiredPropertyExtraData * requiredPropertyExtraDataAt(int idx) const
EnumIterator enumsEnd() const
const Enum * enumAt(int idx) const
RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const
const RequiredPropertyExtraData * requiredPropertyExtraDataTable() const
TableIterator< Signal, Object, &Object::signalAt > SignalIterator
const Binding * bindingsEnd() const
bool hasFlag(Flag flag) const
const Property * propertyTable() const
SignalIterator signalsBegin() const
InlineComponentIterator inlineComponentsEnd() const
const Alias * aliasTable() const
static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nInlineComponents, int nRequiredPropertyExtraData)
const InlineComponent * inlineComponentAt(int idx) const
const Property * propertiesEnd() const
const Binding * bindingTable() const
const Signal * signalAt(int idx) const
const Property * propertiesBegin() const
const quint32_le * functionOffsetTable() const
TableIterator< InlineComponent, Object, &Object::inlineComponentAt > InlineComponentIterator
const InlineComponent * inlineComponentTable() const
InlineComponentIterator inlineComponentsBegin() const
TableIterator< RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt > RequiredPropertyExtraDataIterator
SignalIterator signalsEnd() const
quint32_le_bitfield_union< FlagsField, DefaultPropertyIsAliasField > flagsAndDefaultPropertyIsAlias
const Alias * aliasesEnd() const
const Binding * bindingsBegin() const
RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const
void setHasAliasAsDefaultProperty(bool defaultAlias)
const Alias * aliasesBegin() const
void set(Flags flags, quint32 typeNameIndexOrCommonType)
void setNameIndex(int nameIndex)
void setIsReadOnly(bool isReadOnly)
void setTypeNameIndex(int nameIndex)
void setIsVirtual(bool isVirtual)
quint32_le_bitfield_union< CommonTypeOrTypeNameIndexField, IsRequiredField, IsCommonTypeField, IsListField, IsReadOnlyField > data
quint32_le_bitfield_union< NameIndexField, IsVirtualField, IsOverrideField, IsFinalField > nameIndexAndVirtSpecifiers
void setIsOverride(bool isOverride)
void setIsRequired(bool isRequired)
const Object * objectAt(int idx) const
const Import * importAt(int idx) const
RegExp(quint32 flags, quint32 stringIndex)
Q_DECLARE_FLAGS(Flags, Flag)
bool addToHash(QCryptographicHash *hash, QHash< quintptr, QByteArray > *checksums) const
const RuntimeObject * objectAt(int idx) const
const RuntimeBindingIndex * bindingOrder() const
const RuntimeBinding * bindingTable() const
RuntimeBindingIndex * bindingOrder()
const quint32_le * namedObjectsInComponentTable() const
const Parameter * parametersBegin() const
static int calculateSize(int nParameters)
const Parameter * parametersEnd() const
const Parameter * parameterAt(int idx) const
static int calculateSize(const QString &str)
bool operator==(const TableIterator &rhs) const
bool operator!=(const TableIterator &rhs) const
TableIterator(const Container *container, int index)
TableIterator operator+(int offset) const
const ItemType * operator->() const
int operator-(TableIterator other) const
TableIterator operator-(int offset) const
const quint32_le * stringTable() const
void collectFromObject(const CompiledObject *obj)
TypeReference & add(int nameIndex, const Location &loc)
void collectFromObjects(Iterator it, Iterator end)
quint32_le offsetToIndirectExportEntryTable
quint32_le * translationContextIndex()
const TranslationData * translations() const
const ExportEntry * indirectExportEntryTable() const
const quint64_le * constants() const
QString stringAtInternal(uint idx) const
const quint32_le * functionOffsetTable() const
bool isListPropertyAssignReplaceIfNotDefault() const
bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
const Function * functionAt(int idx) const
const TemplateObject * templateObjectAt(int idx) const
const ExportEntry * starExportEntryTable() const
const Lookup * lookupTable() const
const RegExp * regexpAt(int index) const
const Block * blockAt(int idx) const
const ExportEntry * localExportEntryTable() const
const quint32_le * translationContextIndex() const
const quint32_le * classOffsetTable() const
const quint32_le * moduleRequestTable() const
bool isListPropertyAssignReplace() const
const Class * classAt(int idx) const
const ImportEntry * importEntryTable() const
const QmlUnit * qmlUnit() const
const quint32_le * blockOffsetTable() const
const JSClassMember * jsClassAt(int idx, int *nMembers) const
const quint32_le * templateObjectOffsetTable() const