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
20#include <QtCore/qcryptographichash.h>
21#include <QtCore/qhash.h>
22#include <QtCore/qhashfunctions.h>
23#include <QtCore/qlocale.h>
24#include <QtCore/qscopeguard.h>
25#include <QtCore/qstring.h>
26#include <QtCore/qstringlist.h>
27#include <QtCore/qurl.h>
28#include <QtCore/qvector.h>
29#include <QtCore/qtyperevision.h>
30#include <QtCore/qxpfunctional.h>
31
32#if QT_CONFIG(temporaryfile)
33#include <QtCore/qsavefile.h>
34#endif
35
36#include <private/qendian_p.h>
37#include <private/qqmlnullablevalue_p.h>
38#include <private/qqmlpropertycachevector_p.h>
39#include <private/qqmlrefcount_p.h>
40#include <private/qqmltype_p.h>
41#include <private/qv4compilationunitmapper_p.h>
42#include <private/qv4staticvalue_p.h>
43
44#include <functional>
45#include <limits.h>
46
47QT_BEGIN_NAMESPACE
48
49// Bump this whenever the compiler data structures change in an incompatible way.
50//
51// IMPORTANT:
52//
53// Also change the comment behind the number to describe the latest change. This has the added
54// benefit that if another patch changes the version too, it will result in a merge conflict, and
55// not get removed silently.
56// Also update the comparison functions in qqmlpreviewdiff.cpp when you change the data structures.
57#define QV4_DATA_STRUCTURE_VERSION 0x4f // Add sourceChecksum for content-based cache validation
58
59class QIODevice;
60class QQmlTypeNameCache;
61class QQmlType;
62class QQmlEngine;
64class QQmlScriptData;
65
66namespace QQmlPrivate {
68}
69
70namespace QmlIR {
71struct Document;
72}
73
74namespace QV4 {
75namespace Heap {
76struct Module;
77struct String;
78struct InternalClass;
79};
80
81struct Function;
82class EvalISelFactory;
84
85namespace CompiledData {
86
87// index is per-object binding index
89
90// map from name index
92{
93 bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const;
94};
95
96struct String;
97struct Function;
98struct Lookup;
99struct RegExp;
100struct Unit;
101
102template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
104{
105 TableIterator(const Container *container, int index) : container(container), index(index) {}
106 const Container *container;
107 int index;
108
109 const ItemType *operator->() const { return (container->*IndexedGetter)(index); }
110 ItemType operator*() const {return *operator->();}
111
113 {
114 ++index;
115 return *this;
116 }
117
119 {
121 ++index;
122 return result;
123 }
124
125 TableIterator operator+(int offset) const { return TableIterator(container, index + offset); }
126 TableIterator operator-(int offset) const { return TableIterator(container, index - offset); }
127 int operator-(TableIterator other) const { return index - other.index; }
128
129 bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
130 bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
131};
132
134{
136 Location(quint32 l, quint32 c) : Location()
137 {
138 m_data.set<LineField>(l);
139 m_data.set<ColumnField>(c);
140 Q_ASSERT(m_data.get<LineField>() == l);
141 Q_ASSERT(m_data.get<ColumnField>() == c);
142 }
143
144 inline bool operator<(const Location &other) const {
145 return m_data.get<LineField>() < other.m_data.get<LineField>()
146 || (m_data.get<LineField>() == other.m_data.get<LineField>()
147 && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
148 }
149
150 friend size_t qHash(const Location &location, size_t seed = 0)
151 {
152 return QT_PREPEND_NAMESPACE(qHash)(location.m_data.data(), seed);
153 }
154
155 friend bool comparesEqual(const Location &a, const Location &b) noexcept
156 {
157 return a.m_data.data()== b.m_data.data();
158 }
160
166
167 quint32 line() const { return m_data.get<LineField>(); }
168 quint32 column() const { return m_data.get<ColumnField>(); }
169
170private:
173
174 quint32_le_bitfield_union<LineField, ColumnField> m_data;
175};
176static_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");
177
178struct RegExp
179{
188
190
192 RegExp(quint32 flags, quint32 stringIndex) : RegExp()
193 {
194 m_data.set<FlagsField>(flags);
195 m_data.set<StringIndexField>(stringIndex);
196 }
197
198 quint32 flags() const { return m_data.get<FlagsField>(); }
199 quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
200
201private:
204 quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
205};
206static_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");
207
208struct Lookup
209{
216
217 enum Mode : unsigned int {
220 };
221
222 quint32 type() const { return m_data.get<TypeField>(); }
223 quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
224 quint32 mode() const { return m_data.get<ModeField>(); }
225
227 Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup()
228 {
229 m_data.set<TypeField>(type);
230 m_data.set<ModeField>(mode);
231 m_data.set<NameIndexField>(nameIndex);
232 }
233
234private:
237 // 1 bit left
239 quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data;
240};
241static_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");
242
244{
246
247 void set(quint32 nameOffset, bool isAccessor)
248 {
249 m_data.set<NameOffsetField>(nameOffset);
250 m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
251 }
252
253 quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
254 bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
255
256private:
259 quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
260};
261static_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");
262
264{
266 // JSClassMember[nMembers]
267
268 static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
269};
270static_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");
271
272struct String
273{
275
276 static int calculateSize(const QString &str) {
277 // we cannot enconuter strings larger than INT_MAX anyway, as such a string
278 // would already break in other parts of the compilation process
279 return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7;
280 }
281};
282
283static_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");
284
287 qint32_le line; // signed because debug instructions get negative line numbers
289};
290static_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");
291
292struct Block
293{
298
299 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
300
301 static int calculateSize(int nLocals) {
302 int trailingData = nLocals*sizeof (quint32);
303 size_t size = align(align(sizeof(Block)) + size_t(trailingData));
304 Q_ASSERT(size < INT_MAX);
305 return int(size);
306 }
307
308 static size_t align(size_t a) {
309 return (a + 7) & ~size_t(7);
310 }
311};
312static_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");
313
314enum class NamedBuiltin: unsigned int {
316};
317
318enum class CommonType : unsigned int {
319 // Actual named builtins
329
330 // Optimization for very common other types
332
333 // No type specified or not recognized
335};
336
338{
339 enum Flag {
340 NoFlag = 0x0,
341 Common = 0x1,
342 List = 0x2,
343 };
345
346 void set(Flags flags, quint32 typeNameIndexOrCommonType)
347 {
348 m_data.set<IsListField>(flags.testFlag(List) ? 1 : 0);
349 m_data.set<IndexIsCommonTypeField>(flags.testFlag(Common) ? 1 : 0);
350 m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType);
351 }
352
353 bool indexIsCommonType() const
354 {
355 return m_data.get<IndexIsCommonTypeField>() != 0;
356 }
357
358 bool isList() const
359 {
360 return m_data.get<IsListField>() != 0;
361 }
362
364 {
365 return m_data.get<TypeNameIndexOrCommonTypeField>();
366 }
367
368private:
372 quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data;
373};
374static_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");
375
381static_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");
382
383// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
384// for unaligned access. The ordering of the fields is also from largest to smallest.
386{
387 enum Flags : unsigned int {
388 IsStrict = 0x1,
392 };
393
394 // Absolute offset into file where the code for this function is located.
397
401 quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
406 size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
407 quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
408
412
416
418 {
419 return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement);
420 }
421
422 // Keep all unaligned data at the end
425
426 // quint32 formalsIndex[nFormals]
427 // quint32 localsIndex[nLocals]
428
429 const Parameter *formalsTable() const
430 {
431 return reinterpret_cast<const Parameter *>(
432 reinterpret_cast<const char *>(this) + formalsOffset);
433 }
434 const quint32_le *localsTable() const
435 {
436 return reinterpret_cast<const quint32_le *>(
437 reinterpret_cast<const char *>(this) + localsOffset);
438 }
440 {
441 return reinterpret_cast<const CodeOffsetToLineAndStatement *>(
442 reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset());
443 }
444
445 // --- QQmlPropertyCacheCreator interface
446 const Parameter *formalsBegin() const { return formalsTable(); }
447 const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
448 // ---
449
450 const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
451
452 const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
453
454 static int calculateSize(
455 int nFormals, int nLocals, int nLinesAndStatements, int labelInfoSize, int codeSize)
456 {
457 const size_t trailingData = nFormals * sizeof(Parameter)
458 + (nLocals + labelInfoSize) * sizeof (quint32)
459 + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement);
460 size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
461 Q_ASSERT(size < INT_MAX);
462 return int(size);
463 }
464
465 static size_t align(size_t a) {
466 return (a + 7) & ~size_t(7);
467 }
468};
469static_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");
470
482static_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");
483
484struct Class
485{
492
493 const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
494
495 static int calculateSize(int nStaticMethods, int nMethods) {
496 int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
497 size_t size = align(sizeof(Class) + trailingData);
498 Q_ASSERT(size < INT_MAX);
499 return int(size);
500 }
501
502 static size_t align(size_t a) {
503 return (a + 7) & ~size_t(7);
504 }
505};
506static_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");
507
509{
511
512 static int calculateSize(int size) {
513 int trailingData = 2 * size * sizeof(quint32_le);
514 size_t s = align(sizeof(TemplateObject) + trailingData);
515 Q_ASSERT(s < INT_MAX);
516 return int(s);
517 }
518
519 static size_t align(size_t a) {
520 return (a + 7) & ~size_t(7);
521 }
522
523 const quint32_le *stringTable() const {
524 return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
525 }
526
527 uint stringIndexAt(uint i) const {
528 return stringTable()[i];
529 }
530 uint rawStringIndexAt(uint i) const {
531 return stringTable()[size + i];
532 }
533};
534static_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");
535
544static_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");
545
553static_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");
554
555// Qml data structures
556
565static_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");
566
568{
570
584
599
603
604 void clearFlags() { flagsAndType.set<FlagsField>(0); }
605 void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
606 bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
607 Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
608
609 void setType(Type type) { flagsAndType.set<TypeField>(type); }
610 Type type() const { return Type(flagsAndType.get<TypeField>()); }
611
612 union {
613 bool b;
615 qint32_le resolvedEnumValue; // used when Type_Number and IsResolvedEnum: enum values are
616 // integers and stored inline rather than in the constant table
617 quint32_le compiledScriptIndex; // used when Type_Script
619 quint32_le translationDataIndex; // used when Type_Translation
621 } value;
622 quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
623
626
628 {
629 const Flags bindingFlags = flags();
630 return bindingFlags & IsSignalHandlerExpression
631 || bindingFlags & IsSignalHandlerObject
632 || bindingFlags & IsPropertyObserver;
633 }
634
635 bool isValueBinding() const
636 {
637 switch (type()) {
640 return false;
641 default:
643 }
644 }
645
648
649 bool isSignalHandler() const
650 {
652 Q_ASSERT(!isValueBinding());
653 Q_ASSERT(!isAttachedProperty());
654 Q_ASSERT(!isGroupProperty());
655 return true;
656 }
657 return false;
658 }
659
661 {
663 Q_ASSERT(!isValueBinding());
664 Q_ASSERT(!isSignalHandler());
665 Q_ASSERT(!isGroupProperty());
666 return true;
667 }
668 return false;
669 }
670
671 bool isGroupProperty() const
672 {
673 if (type() == Type_GroupProperty) {
674 Q_ASSERT(!isValueBinding());
675 Q_ASSERT(!isSignalHandler());
676 Q_ASSERT(!isAttachedProperty());
677 return true;
678 }
679 return false;
680 }
681
683
684 //reverse of Lexer::singleEscape()
685 static QString escapedString(const QString &string)
686 {
687 QString tmp = QLatin1String("\"");
688 for (int i = 0; i < string.size(); ++i) {
689 const QChar &c = string.at(i);
690 switch (c.unicode()) {
691 case 0x08:
692 tmp += QLatin1String("\\b");
693 break;
694 case 0x09:
695 tmp += QLatin1String("\\t");
696 break;
697 case 0x0A:
698 tmp += QLatin1String("\\n");
699 break;
700 case 0x0B:
701 tmp += QLatin1String("\\v");
702 break;
703 case 0x0C:
704 tmp += QLatin1String("\\f");
705 break;
706 case 0x0D:
707 tmp += QLatin1String("\\r");
708 break;
709 case 0x22:
710 tmp += QLatin1String("\\\"");
711 break;
712 case 0x27:
713 tmp += QLatin1String("\\\'");
714 break;
715 case 0x5C:
716 tmp += QLatin1String("\\\\");
717 break;
718 default:
719 tmp += c;
720 break;
721 }
722 }
723 tmp += QLatin1Char('\"');
724 return tmp;
725 }
726
728 {
729 const Binding::Type bindingType = type();
730 return bindingType == Type_Translation || bindingType == Type_TranslationById;
731 }
733
734 bool isNumberBinding() const { return type() == Type_Number; }
735
736 bool valueAsBoolean() const
737 {
738 if (type() == Type_Boolean)
739 return value.b;
740 return false;
741 }
742};
743
744static_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");
745
752
753static_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");
754
760static_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");
761
762struct Enum
763{
767
768 const EnumValue *enumValueAt(int idx) const {
769 return reinterpret_cast<const EnumValue*>(this + 1) + idx;
770 }
771
772 static int calculateSize(int nEnumValues) {
773 return (sizeof(Enum)
774 + nEnumValues * sizeof(EnumValue)
775 + 7) & ~0x7;
776 }
777
778 // --- QQmlPropertyCacheCreatorInterface
779 const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
780 const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
781 int enumValueCount() const { return nEnumValues; }
782 // ---
783};
784static_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");
785
786struct Signal
787{
791 // Parameter parameters[1];
792
793 const Parameter *parameterAt(int idx) const {
794 return reinterpret_cast<const Parameter*>(this + 1) + idx;
795 }
796
797 static int calculateSize(int nParameters) {
798 return (sizeof(Signal)
799 + nParameters * sizeof(Parameter)
800 + 7) & ~0x7;
801 }
802
803 // --- QQmlPropertyCacheCceatorInterface
804 const Parameter *parametersBegin() const { return parameterAt(0); }
805 const Parameter *parametersEnd() const { return parameterAt(nParameters); }
806 int parameterCount() const { return nParameters; }
807 // ---
808};
809static_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");
810
811/*
812 * We aim to minimize the size of a struct as much as possible, while preserving at least 28 bits
813 * for each index.
814 *
815 * Note that Name and Type indices are provided by StringTableGenerator, containing a hashmap
816 * (and a list) of unique strings within one Compilation Unit. It sounds rather unrealistic to have
817 * 2^28 (260+ million) unique strings within 1 CU (even if it's some form of global registry), not
818 * to mention the amount of memory needed to maintain such a StringTableGenerator.
819 * Therefore, after some preliminary analysis, it seems that even 20 bits
820 * should be a rather conservative cap.
821 *
822 * However it doesn't seem to easily provide many benefits atm other than better (logically) grouped
823 * unions like, let's say nameIndexAndAttributes.
824 *
825 * Atm 32-bit member nameIndexAndVirtSpecifiers looks smth like this:
826 *
827 * NameIndexField IsVirtualField IsOverrideField IsFinalField
828 * |10100000101000111000001110000| 0 | 1 | 0 |
829 *
830 */
832{
833private:
838
844
845public:
855
856 quint32 nameIndex() const { return nameIndexAndVirtSpecifiers.get<NameIndexField>(); }
857 void setNameIndex(int nameIndex) { nameIndexAndVirtSpecifiers.set<NameIndexField>(nameIndex); }
858
859 bool isVirtual() const { return nameIndexAndVirtSpecifiers.get<IsVirtualField>(); }
860 void setIsVirtual(bool isVirtual)
861 {
862 nameIndexAndVirtSpecifiers.set<IsVirtualField>(isVirtual ? 1 : 0);
863 }
864
865 bool isOverride() const { return nameIndexAndVirtSpecifiers.get<IsOverrideField>(); }
866 void setIsOverride(bool isOverride)
867 {
868 nameIndexAndVirtSpecifiers.set<IsOverrideField>(isOverride ? 1 : 0);
869 }
870
871 bool isFinal() const { return nameIndexAndVirtSpecifiers.get<IsFinalField>(); }
872 void setIsFinal(bool isFinal) { nameIndexAndVirtSpecifiers.set<IsFinalField>(isFinal ? 1 : 0); }
873
875 {
876 data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t));
877 data.set<IsCommonTypeField>(true);
878 }
879
881 if (isCommonType())
882 return CommonType(data.get<CommonTypeOrTypeNameIndexField>());
883 return CommonType::Invalid;
884 }
885
886 void setTypeNameIndex(int nameIndex)
887 {
888 data.set<CommonTypeOrTypeNameIndexField>(nameIndex);
889 data.set<IsCommonTypeField>(false);
890 }
891
892 int typeNameIndex() const
893 {
894 return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>();
895 }
896
897 bool isCommonType() const { return data.get<IsCommonTypeField>(); }
898 uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); }
899
900 bool isList() const { return data.get<IsListField>(); }
901 void setIsList(bool isList) { data.set<IsListField>(isList); }
902
903 bool isRequired() const { return data.get<IsRequiredField>(); }
904 void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
905
906 bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
907 void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
908};
909static_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");
910
914
915static_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");
916
917struct Alias
918{
919 bool isReadOnly() const { return m_nameIndexAndFlags.get<IsReadOnlyField>(); }
920 void setIsReadOnly(bool isReadOnly) { m_nameIndexAndFlags.set<IsReadOnlyField>(isReadOnly); }
921
922 quint32 nameIndex() const { return m_nameIndexAndFlags.get<NameIndexField>(); }
923 void setNameIndex(quint32 nameIndex)
924 {
925 m_nameIndexAndFlags.set<NameIndexField>(nameIndex);
926 }
927
928 quint32 idIndex() const { return m_idIndexField; }
929 void setIdIndex(quint32 idIndex) { m_idIndexField = idIndex; }
930
931 quint32 propertyNameIndex() const { return m_propertyNameIndex; }
932 void setPropertyNameIndex(quint32 propertyNameIndex)
933 {
934 m_propertyNameIndex = propertyNameIndex;
935 }
936
937 Location location() const { return m_location; }
938 void setLocation(Location location) { m_location = location; }
939
940 Location referenceLocation() const { return m_referenceLocation; }
941 void setReferenceLocation(Location referenceLocation)
942 {
943 m_referenceLocation = referenceLocation;
944 }
945
946private:
949
950 quint32_le_bitfield_union<NameIndexField, IsReadOnlyField> m_nameIndexAndFlags;
951 quint32_le m_idIndexField;
952 quint32_le m_propertyNameIndex; // string index
953 Location m_location;
954 Location m_referenceLocation;
955};
956static_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");
957
958struct Object
959{
960private:
964public:
965 enum Flag : unsigned int {
966 NoFlag = 0x0,
967 IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
968 HasDeferredBindings = 0x2, // any of the bindings are deferred
972 };
974
975 // Depending on the use, this may be the type name to instantiate before instantiating this
976 // object. For grouped properties the type name will be empty and for attached properties
977 // it will be the name of the attached type.
982 qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
990 quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
991 quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
1003// Function[]
1004// Property[]
1005// Signal[]
1006// Binding[]
1007// InlineComponent[]
1008// RequiredPropertyExtraData[]
1009
1010 Flags flags() const
1011 {
1012 return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>());
1013 }
1014
1015 bool hasFlag(Flag flag) const
1016 {
1017 return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag;
1018 }
1019
1020 void setFlag(Flag flag)
1021 {
1022 flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(
1023 flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag);
1024 }
1025
1026 void setFlags(Flags flags)
1027 {
1028 flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags);
1029 }
1030
1032 {
1033 return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>();
1034 }
1035
1036 void setHasAliasAsDefaultProperty(bool defaultAlias)
1037 {
1038 flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias);
1039 }
1040
1042 {
1043 return flagsAndDefaultPropertyIsAliasAndId.get<IdField>();
1044 }
1045
1046 void setObjectId(qint32 id)
1047 {
1048 flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id);
1049 }
1050
1051
1052 static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
1053 {
1054 return ( sizeof(Object)
1055 + nFunctions * sizeof(quint32)
1056 + nProperties * sizeof(Property)
1057 + nAliases * sizeof(Alias)
1058 + nEnums * sizeof(quint32)
1059 + nSignals * sizeof(quint32)
1060 + nBindings * sizeof(Binding)
1061 + nNamedObjectsInComponent * sizeof(int)
1062 + nInlineComponents * sizeof(InlineComponent)
1063 + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
1064 + 0x7
1065 ) & ~0x7;
1066 }
1067
1069 {
1070 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
1071 }
1072
1074 {
1075 return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
1076 }
1077
1078 const Alias *aliasTable() const
1079 {
1080 return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
1081 }
1082
1083 const Binding *bindingTable() const
1084 {
1085 return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
1086 }
1087
1088 const Enum *enumAt(int idx) const
1089 {
1090 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
1091 const quint32_le offset = offsetTable[idx];
1092 return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
1093 }
1094
1095 const Signal *signalAt(int idx) const
1096 {
1097 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
1098 const quint32_le offset = offsetTable[idx];
1099 return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
1100 }
1101
1103 {
1104 return inlineComponentTable() + idx;
1105 }
1106
1108 {
1109 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
1110 }
1111
1113 {
1114 return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
1115 }
1116
1121
1123 {
1124 return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
1125 }
1126
1127 // --- QQmlPropertyCacheCreator interface
1128 int propertyCount() const { return nProperties; }
1129 int aliasCount() const { return nAliases; }
1130 int enumCount() const { return nEnums; }
1131 int signalCount() const { return nSignals; }
1132 int functionCount() const { return nFunctions; }
1133 int inlineComponentCount() const { return nInlineComponents; }
1134
1135 const Binding *bindingsBegin() const { return bindingTable(); }
1136 const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
1137 int bindingCount() const { return nBindings; }
1138
1139 const Property *propertiesBegin() const { return propertyTable(); }
1140 const Property *propertiesEnd() const { return propertyTable() + nProperties; }
1141
1142 const Alias *aliasesBegin() const { return aliasTable(); }
1143 const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
1144
1146 EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
1147 EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
1148
1150 SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
1151 SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
1152
1154 InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
1155 InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
1156
1158 RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); }
1159 RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }
1160
1161 int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
1162 // ---
1163};
1164static_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");
1165
1167{
1168 enum ImportType : unsigned int {
1173 };
1175
1178
1182
1184 {
1185 type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0;
1186 }
1187};
1188static_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");
1189
1191{
1196
1197 const Import *importAt(int idx) const {
1198 return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
1199 }
1200
1201 const Object *objectAt(int idx) const {
1202 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
1203 const quint32_le offset = offsetTable[idx];
1204 return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
1205 }
1206};
1207static_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");
1208
1209static const char magic_str[] = "qv4cdata";
1210
1211struct Unit
1212{
1213 // DO NOT CHANGE THESE FIELDS EVER
1214 char magic[8];
1216 // END DO NOT CHANGE THESE FIELDS EVER
1217
1218 quint32_le reserved; // For predictable alignment and size. Used to be Qt version.
1219
1220 // A sourceTimeStamp of -1 marks a unit that is validated by source content hashing rather
1221 // than by time stamp. In that case sourceChecksum holds the checksum of the source code and
1222 // is compared against the freshly computed checksum of the source on load. This is used for
1223 // cache files generated at run time, where the source's time stamp may be unreliable (e.g.
1224 // reproducible builds that pin mtimes via SOURCE_DATE_EPOCH). Units generated by qmlcachegen
1225 // at compile time keep their actual time stamp and leave sourceChecksum zeroed.
1227 quint32_le unitSize; // Size of the Unit and any depending data.
1228
1229 // Kept before md5Checksum, and therefore outside its coverage, so that it can be patched in
1230 // when saving a unit to disk without invalidating md5Checksum.
1232
1233 char md5Checksum[16]; // checksum of all bytes following this field.
1235
1236 enum : unsigned int {
1238 StaticData = 0x2, // Unit data persistent in memory?
1240 IsSharedLibrary = 0x8, // .pragma shared?
1242 PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation
1243 IsStrict = 0x40,
1254 };
1289
1291
1292 /* QML specific fields */
1293
1294 const QmlUnit *qmlUnit() const {
1295 return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
1296 }
1297
1299 return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
1300 }
1301
1302 bool isSingleton() const {
1303 return flags & Unit::IsSingleton;
1304 }
1305
1307 // ListPropertyAssignReplace is the combination of both replace bits, so it must be tested
1308 // for an exact match.
1309 return (flags & Unit::ListPropertyAssignReplace) == Unit::ListPropertyAssignReplace;
1310 }
1311
1313 return flags & Unit::ListPropertyAssignReplaceIfNotDefault;
1314 }
1315 /* end QML specific fields*/
1316
1317 QString stringAtInternal(uint idx) const {
1318 Q_ASSERT(idx < stringTableSize);
1319 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
1320 const quint32_le offset = offsetTable[idx];
1321 const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
1322 Q_ASSERT(str->size >= 0);
1323#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1324 const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
1325 if (flags & StaticData)
1326 return QString::fromRawData(characters, str->size);
1327 return QString(characters, str->size);
1328#else
1329 const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
1330 QString qstr(str->size, Qt::Uninitialized);
1331 QChar *ch = qstr.data();
1332 for (int i = 0; i < str->size; ++i)
1333 ch[i] = QChar(quint16(characters[i]));
1334 return qstr;
1335#endif
1336 }
1337
1338 const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
1339 const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
1340 const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
1341 const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
1342
1343 const Function *functionAt(int idx) const {
1344 const quint32_le *offsetTable = functionOffsetTable();
1345 const quint32_le offset = offsetTable[idx];
1346 return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
1347 }
1348
1349 const Class *classAt(int idx) const {
1350 const quint32_le *offsetTable = classOffsetTable();
1351 const quint32_le offset = offsetTable[idx];
1352 return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
1353 }
1354
1355 const TemplateObject *templateObjectAt(int idx) const {
1356 const quint32_le *offsetTable = templateObjectOffsetTable();
1357 const quint32_le offset = offsetTable[idx];
1358 return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
1359 }
1360
1361 const Block *blockAt(int idx) const {
1362 const quint32_le *offsetTable = blockOffsetTable();
1363 const quint32_le offset = offsetTable[idx];
1364 return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
1365 }
1366
1367 const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
1368 const RegExp *regexpAt(int index) const {
1369 return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
1370 }
1371 const quint64_le *constants() const {
1372 return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
1373 }
1374
1375 const JSClassMember *jsClassAt(int idx, int *nMembers) const {
1376 const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
1377 const quint32_le offset = offsetTable[idx];
1378 const char *ptr = reinterpret_cast<const char *>(this) + offset;
1379 const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
1380 *nMembers = klass->nMembers;
1381 return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
1382 }
1383
1385 return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
1386 }
1387
1389 if ( translationTableSize == 0)
1390 return nullptr;
1391 return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this))
1392 + offsetToTranslationTable
1393 + translationTableSize * sizeof(CompiledData::TranslationData)); }
1394
1396 if ( translationTableSize == 0)
1397 return nullptr;
1398 return reinterpret_cast<quint32_le*>((reinterpret_cast<char *>(this))
1399 + offsetToTranslationTable
1400 + translationTableSize * sizeof(CompiledData::TranslationData)); }
1401
1402 const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
1403 const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
1404 const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
1405 const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
1406
1407 const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
1408
1409 bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
1410};
1411
1412static_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");
1413
1415{
1417 : location(loc)
1418 , needsCreation(false)
1419 , errorWhenNotFound(false)
1420 {}
1421 Location location; // first use
1422 bool needsCreation : 1; // whether the type needs to be creatable or not
1424};
1425
1426// Map from name index to location of first use.
1428{
1429 TypeReference &add(int nameIndex, const Location &loc) {
1430 Iterator it = find(nameIndex);
1431 if (it != end())
1432 return *it;
1433 return *insert(nameIndex, loc);
1434 }
1435
1436 template <typename CompiledObject>
1437 void collectFromObject(const CompiledObject *obj)
1438 {
1439 if (obj->inheritedTypeNameIndex != 0) {
1440 TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
1441 r.needsCreation = true;
1442 r.errorWhenNotFound = true;
1443 }
1444
1445 auto binding = obj->bindingsBegin();
1446 auto const bindingEnd = obj->bindingsEnd();
1447 for ( ; binding != bindingEnd; ++binding) {
1449 this->add(binding->propertyNameIndex, binding->location);
1450 }
1451
1452 auto ic = obj->inlineComponentsBegin();
1453 auto const icEnd = obj->inlineComponentsEnd();
1454 for (; ic != icEnd; ++ic) {
1455 this->add(ic->nameIndex, ic->location);
1456 }
1457 }
1458
1459 template <typename Iterator>
1460 void collectFromObjects(Iterator it, Iterator end)
1461 {
1462 for (; it != end; ++it)
1463 collectFromObject(*it);
1464 }
1465};
1466
1468
1470
1472 InlineComponentData(const QQmlType &qmlType, int objectIndex, int nameIndex)
1473 : qmlType(qmlType)
1474 , objectIndex(objectIndex)
1475 , nameIndex(nameIndex)
1476 {}
1477
1478 QQmlType qmlType;
1479 int objectIndex = -1;
1480 int nameIndex = -1;
1481};
1482
1484{
1486
1487 const Unit *data = nullptr;
1488 const QmlUnit *qmlData = nullptr;
1492
1493 // pointers either to data->constants() or little-endian memory copy.
1494 const StaticValue *constants = nullptr;
1495
1497
1499
1500 // index is object index. This allows fast access to the
1501 // property data when initializing bindings, avoiding expensive
1502 // lookups by string (property name).
1504
1507
1509
1510 QQmlType qmlType;
1511
1513
1514public:
1515 // --- interface for QQmlPropertyCacheCreator
1519
1520 // Empty dummy. We don't need to do this when loading from cache.
1522 {
1523 public:
1524 void insert(int, int) {}
1525 void clear() {}
1526
1527 // We have already checked uniqueness of IDs when creating the CU
1528 bool contains(int) { return false; }
1529 };
1530
1531 explicit CompilationUnit(const Unit *unitData,
1532 const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions,
1533 LookupValidationFn validateLookupSignatures,
1534 const QString &fileName = QString(),
1535 const QString &finalUrlString = QString())
1536 : CompilationUnit(unitData, fileName, finalUrlString)
1537 {
1538 this->aotCompiledFunctions = aotCompiledFunctions;
1539 this->validateLookupSignatures = validateLookupSignatures;
1540 }
1541
1543 const Unit *unitData = nullptr, const QString &fileName = QString(),
1544 const QString &finalUrlString = QString());
1545
1547
1548 const Unit *unitData() const { return data; }
1549
1550 void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
1551 const QString &fileName = QString(), const QString &finalUrlString = QString())
1552 {
1553 data = unitData;
1554 qmlData = nullptr;
1555#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1556 delete [] constants;
1557#endif
1558 constants = nullptr;
1559 m_fileName.clear();
1560 m_finalUrlString.clear();
1561 if (!data)
1562 return;
1563
1564 qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
1565
1566#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1567 StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
1568 const quint64_le *littleEndianConstants = data->constants();
1569 for (uint i = 0; i < data->constantTableSize; ++i)
1570 bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
1571 constants = bigEndianConstants;
1572#else
1573 constants = reinterpret_cast<const StaticValue*>(data->constants());
1574#endif
1575
1576 m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
1577 m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
1578 }
1579
1580 QString stringAt(uint index) const
1581 {
1582 if (index < data->stringTableSize)
1583 return data->stringAtInternal(index);
1584
1585 const qsizetype dynamicIndex = index - data->stringTableSize;
1586 Q_ASSERT(dynamicIndex < dynamicStrings.size());
1587 return dynamicStrings.at(dynamicIndex);
1588 }
1589
1590 QString fileName() const { return m_fileName; }
1591 QString finalUrlString() const { return m_finalUrlString; }
1592
1594 {
1595 using namespace CompiledData;
1596 switch (binding->type()) {
1597 case Binding::Type_Script:
1598 case Binding::Type_String:
1599 return stringAt(binding->stringIndex);
1600 case Binding::Type_Null:
1601 return QStringLiteral("null");
1603 return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
1604 case Binding::Type_Number:
1605 return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
1607 return QString();
1608 case Binding::Type_TranslationById:
1609 case Binding::Type_Translation:
1610 return stringAt(data->translations()[binding->value.translationDataIndex].stringIndex);
1611 default:
1612 break;
1613 }
1614 return QString();
1615 }
1616
1618 {
1619 return (binding->type() == CompiledData::Binding::Type_String)
1620 ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
1621 : bindingValueAsString(binding);
1622 }
1623
1624 double bindingValueAsNumber(const CompiledData::Binding *binding) const
1625 {
1627 return 0.0;
1629 return binding->value.resolvedEnumValue;
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 // Returns the index of the implicit component wrapper, or -1.
1704 // Scans property caches at indices >= objectCount().
1705 int implicitComponentForObject(int index) const
1706 {
1707 for (int i = objectCount(), end = propertyCaches.count(); i < end; ++i) {
1708 const QQmlPropertyData *p = propertyCaches.at(i)->defaultProperty();
1709 Q_ASSERT(p && p->isComponentWrapper());
1710 if (p->wrappedObjectIndex() == index)
1711 return i;
1712 }
1713 return -1;
1714 }
1715
1716 int inlineComponentId(const QString &inlineComponentName) const
1717 {
1718 for (uint i = 0; i < qmlData->nObjects; ++i) {
1719 auto *object = qmlData->objectAt(i);
1720 for (auto it = object->inlineComponentsBegin(), end = object->inlineComponentsEnd();
1721 it != end; ++it) {
1722 if (stringAt(it->nameIndex) == inlineComponentName)
1723 return it->objectIndex;
1724 }
1725 }
1726 return -1;
1727 }
1728
1729 void finalizeCompositeType(const QQmlType &type);
1730
1731 bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
1732
1743
1748
1753
1755 {
1757 }
1758
1763
1765 {
1767 }
1768
1770 {
1772 }
1773
1774 bool isESModule() const
1775 {
1777 }
1778
1779 bool isSharedLibrary() const
1780 {
1782 }
1783
1785 {
1786 FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
1787 : unit(unit), object(object), index(index) {}
1791
1793 {
1794 return unit->functionAt(object->functionOffsetTable()[index]);
1795 }
1796
1797 void operator++() { ++index; }
1798 bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
1799 bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
1800 };
1801
1803 {
1804 return FunctionIterator(unitData(), object, 0);
1805 }
1806
1808 {
1809 return FunctionIterator(unitData(), object, object->nFunctions);
1810 }
1811
1812 QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
1813 QMetaType metaType() const { return qmlType.typeId(); }
1814
1815private:
1816 QString m_fileName; // initialized from data->sourceFileIndex
1817 QString m_finalUrlString; // initialized from data->finalUrlIndex
1818
1819 mutable QQmlNullableValue<QUrl> m_url;
1820 mutable QQmlNullableValue<QUrl> m_finalUrl;
1821};
1822
1824{
1826public:
1832
1834
1835 template<typename Char>
1836 bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
1837 {
1838 const quint32_le oldFlags = mutableFlags();
1839 auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
1840 mutableFlags() |= temporaryFlags;
1841 return writer(data<Char>(), size());
1842 }
1843
1844 static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
1845 QString *errorString)
1846 {
1847#if QT_CONFIG(temporaryfile)
1848 QSaveFile cacheFile(outputFileName);
1849 if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
1850 || cacheFile.write(data, size) != size
1851 || !cacheFile.commit()) {
1852 *errorString = cacheFile.errorString();
1853 return false;
1854 }
1855
1856 errorString->clear();
1857 return true;
1858#else
1859 Q_UNUSED(outputFileName);
1860 *errorString = QStringLiteral("features.temporaryfile is disabled.");
1861 return false;
1862#endif
1863 }
1864
1865private:
1866 const Unit *unit;
1867 quint32 temporaryFlags;
1868
1869 quint32_le &mutableFlags() const
1870 {
1871 return const_cast<Unit *>(unit)->flags;
1872 }
1873
1874 template<typename Char>
1875 const Char *data() const
1876 {
1877 Q_STATIC_ASSERT(sizeof(Char) == 1);
1878 const Char *dataPtr;
1879 memcpy(&dataPtr, &unit, sizeof(dataPtr));
1880 return dataPtr;
1881 }
1882
1883 quint32 size() const
1884 {
1885 return unit->unitSize;
1886 }
1887};
1888
1889
1890} // CompiledData namespace
1891} // QV4 namespace
1892
1895
1896QT_END_NAMESPACE
1897
1898#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
double bindingValueAsNumber(const CompiledData::Binding *binding) const
void finalizeCompositeType(const QQmlType &type)
ResolvedTypeReference * resolvedType(int id) const
const CompiledData::Function CompiledFunction
const QQmlPrivate::AOTCompiledFunction * aotCompiledFunctions
int implicitComponentForObject(int index) const
ResolvedTypeReferenceMap resolvedTypes
QList< BindingPropertyData > bindingPropertyDataPerObject
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) 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
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
CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions, LookupValidationFn validateLookupSignatures, const QString &fileName=QString(), const QString &finalUrlString=QString())
QList< QQmlRefPointer< QQmlScriptData > > dependentScripts
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
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)
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
quint32_le_bitfield_union< FlagsField, DefaultPropertyIsAliasField, IdField > flagsAndDefaultPropertyIsAliasAndId
InlineComponentIterator inlineComponentsEnd() const
const Alias * aliasTable() const
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
static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
TableIterator< InlineComponent, Object, &Object::inlineComponentAt > InlineComponentIterator
const InlineComponent * inlineComponentTable() const
InlineComponentIterator inlineComponentsBegin() const
TableIterator< RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt > RequiredPropertyExtraDataIterator
SignalIterator signalsEnd() const
const Alias * aliasesEnd() const
const Binding * bindingsBegin() const
RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const
void setHasAliasAsDefaultProperty(bool defaultAlias)
const Alias * aliasesBegin() const
const quint32_le * namedObjectsInComponentTable() 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 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