1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 #ifndef QV4COMPILEDDATA_P_H
40 #define QV4COMPILEDDATA_P_H
41 
42 //
43 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the Qt API.  It exists purely as an
47 // implementation detail.  This header file may change from version to
48 // version without notice, or even be removed.
49 //
50 // We mean it.
51 //
52 
53 #include <functional>
54 
55 #include <QtCore/qstring.h>
56 #include <QtCore/qscopeguard.h>
57 #include <QtCore/qvector.h>
58 #include <QtCore/qstringlist.h>
59 #include <QtCore/qhash.h>
60 
61 #if QT_CONFIG(temporaryfile)
62 #include <QtCore/qsavefile.h>
63 #endif
64 
65 #include <private/qendian_p.h>
66 #include <private/qv4staticvalue_p.h>
67 #include <functional>
68 
69 QT_BEGIN_NAMESPACE
70 
71 // Bump this whenever the compiler data structures change in an incompatible way.
72 //
73 // IMPORTANT:
74 //
75 // Also change the comment behind the number to describe the latest change. This has the added
76 // benefit that if another patch changes the version too, it will result in a merge conflict, and
77 // not get removed silently.
78 #define QV4_DATA_STRUCTURE_VERSION 0x29// support additional required property features
79 
80 class QIODevice;
81 class QQmlTypeNameCache;
82 class QQmlType;
83 class QQmlEngine;
84 
85 namespace QmlIR {
86 struct Document;
87 }
88 
89 namespace QV4 {
90 namespace Heap {
91 struct Module;
92 struct String;
93 struct InternalClass;
94 };
95 
96 struct Function;
97 class EvalISelFactory;
98 
99 namespace CompiledData {
100 
101 struct String;
102 struct Function;
103 struct Lookup;
104 struct RegExp;
105 struct Unit;
106 
107 template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
108 struct TableIterator
109 {
TableIteratorTableIterator110     TableIterator(const Container *container, int index) : container(container), index(index) {}
111     const Container *container;
112     int index;
113 
114     const ItemType *operator->() { return (container->*IndexedGetter)(index); }
115     ItemType operator*() {return *operator->();}
116     void operator++() { ++index; }
117     bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
118     bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
119 };
120 
121 struct Location
122 {
123     union {
124         quint32 _dummy;
125         quint32_le_bitfield<0, 20> line;
126         quint32_le_bitfield<20, 12> column;
127     };
128 
LocationLocation129     Location() : _dummy(0) { }
130 
131     inline bool operator<(const Location &other) const {
132         return line < other.line ||
133                (line == other.line && column < other.column);
134     }
135 };
136 static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
137 
138 struct RegExp
139 {
140     enum Flags : unsigned int {
141         RegExp_NoFlags    = 0x0,
142         RegExp_Global     = 0x01,
143         RegExp_IgnoreCase = 0x02,
144         RegExp_Multiline  = 0x04,
145         RegExp_Unicode    = 0x08,
146         RegExp_Sticky     = 0x10
147     };
148     union {
149         quint32 _dummy;
150         quint32_le_bitfield<0, 5> flags;
151         quint32_le_bitfield<5, 27> stringIndex;
152     };
153 
RegExpRegExp154     RegExp() : _dummy(0) { }
155 };
156 static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
157 
158 struct Lookup
159 {
160     enum Type : unsigned int {
161         Type_Getter = 0,
162         Type_Setter = 1,
163         Type_GlobalGetter = 2,
164         Type_QmlContextPropertyGetter = 3
165     };
166 
167     union {
168         quint32 _dummy;
169         quint32_le_bitfield<0, 4> type_and_flags;
170         quint32_le_bitfield<4, 28> nameIndex;
171     };
172 
LookupLookup173     Lookup() : _dummy(0) { }
174 };
175 static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
176 
177 struct JSClassMember
178 {
179     union {
180         quint32 _dummy;
181         quint32_le_bitfield<0, 31> nameOffset;
182         quint32_le_bitfield<31, 1> isAccessor;
183     };
184 
JSClassMemberJSClassMember185     JSClassMember() : _dummy(0) { }
186 };
187 static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
188 
189 struct JSClass
190 {
191     quint32_le nMembers;
192     // JSClassMember[nMembers]
193 
calculateSizeJSClass194     static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
195 };
196 static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
197 
198 // This data structure is intended to be binary compatible with QStringData/QStaticStringData on
199 // 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped
200 // from a file must be castable to a QStringData regardless of the pointer size. With the first
201 // few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a
202 // ptrdiff_t and thus variable in size.
203 // On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while
204 // on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain
205 // the same value.
206 struct String
207 {
208     qint32_le refcount; // -1
209     qint32_le size;
210     quint32_le allocAndCapacityReservedFlag; // 0
211     quint32_le offsetOn32Bit;
212     quint64_le offsetOn64Bit;
213     // uint16 strdata[]
214 
calculateSizeString215     static int calculateSize(const QString &str) {
216         return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
217     }
218 };
219 static_assert(sizeof(String) == 24, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
220 
221 // Ensure compatibility with QString
222 static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location");
223 static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location");
224 static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location");
225 static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location");
226 #if QT_POINTER_SIZE == 8
227 static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location");
228 #else
229 static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location");
230 #endif
231 
232 struct CodeOffsetToLine {
233     quint32_le codeOffset;
234     quint32_le line;
235 };
236 static_assert(sizeof(CodeOffsetToLine) == 8, "CodeOffsetToLine structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
237 
238 struct Block
239 {
240     quint32_le nLocals;
241     quint32_le localsOffset;
242     quint16_le sizeOfLocalTemporalDeadZone;
243     quint16_le padding;
244 
localsTableBlock245     const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
246 
calculateSizeBlock247     static int calculateSize(int nLocals) {
248         int trailingData = nLocals*sizeof (quint32);
249         size_t size = align(align(sizeof(Block)) + size_t(trailingData));
250         Q_ASSERT(size < INT_MAX);
251         return int(size);
252     }
253 
alignBlock254     static size_t align(size_t a) {
255         return (a + 7) & ~size_t(7);
256     }
257 };
258 static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
259 
260 enum class BuiltinType : unsigned int {
261     Var = 0, Variant, Int, Bool, Real, String, Url, Color,
262     Font, Time, Date, DateTime, Rect, Point, Size,
263     Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin
264 };
265 
266 struct ParameterType
267 {
268     union {
269         quint32 _dummy;
270         quint32_le_bitfield<0, 1> indexIsBuiltinType;
271         quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
272     };
273 };
274 static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
275 
276 struct Parameter
277 {
278     quint32_le nameIndex;
279     ParameterType type;
280 };
281 static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
282 
283 // Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
284 // for unaligned access. The ordering of the fields is also from largest to smallest.
285 struct Function
286 {
287     enum Flags : unsigned int {
288         IsStrict            = 0x1,
289         IsArrowFunction     = 0x2,
290         IsGenerator         = 0x4
291     };
292 
293     // Absolute offset into file where the code for this function is located.
294     quint32_le codeOffset;
295     quint32_le codeSize;
296 
297     quint32_le nameIndex;
298     quint16_le length;
299     quint16_le nFormals;
300     quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
301     ParameterType returnType;
302     quint32_le localsOffset;
303     quint16_le nLocals;
304     quint16_le nLineNumbers;
lineNumberOffsetFunction305     size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
306     quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
307 
308     quint32_le nRegisters;
309     Location location;
310     quint32_le nLabelInfos;
311 
312     quint16_le sizeOfLocalTemporalDeadZone;
313     quint16_le firstTemporalDeadZoneRegister;
314     quint16_le sizeOfRegisterTemporalDeadZone;
315 
labelInfosOffsetFunction316     size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
317 
318     // Keep all unaligned data at the end
319     quint8 flags;
320     quint8 padding1;
321 
322     //    quint32 formalsIndex[nFormals]
323     //    quint32 localsIndex[nLocals]
324 
formalsTableFunction325     const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); }
localsTableFunction326     const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
lineNumberTableFunction327     const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
328 
329     // --- QQmlPropertyCacheCreator interface
formalsBeginFunction330     const Parameter *formalsBegin() const { return formalsTable(); }
formalsEndFunction331     const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
332     // ---
333 
labelInfoTableFunction334     const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
335 
codeFunction336     const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
337 
calculateSizeFunction338     static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
339         int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
340                 + nLines*sizeof(CodeOffsetToLine);
341         size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
342         Q_ASSERT(size < INT_MAX);
343         return int(size);
344     }
345 
alignFunction346     static size_t align(size_t a) {
347         return (a + 7) & ~size_t(7);
348     }
349 };
350 static_assert(sizeof(Function) == 56, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
351 
352 struct Method {
353     enum Type {
354         Regular,
355         Getter,
356         Setter
357     };
358 
359     quint32_le name;
360     quint32_le type;
361     quint32_le function;
362 };
363 static_assert(sizeof(Method) == 12, "Method structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
364 
365 struct Class
366 {
367     quint32_le nameIndex;
368     quint32_le scopeIndex;
369     quint32_le constructorFunction;
370     quint32_le nStaticMethods;
371     quint32_le nMethods;
372     quint32_le methodTableOffset;
373 
methodTableClass374     const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
375 
calculateSizeClass376     static int calculateSize(int nStaticMethods, int nMethods) {
377         int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
378         size_t size = align(sizeof(Class) + trailingData);
379         Q_ASSERT(size < INT_MAX);
380         return int(size);
381     }
382 
alignClass383     static size_t align(size_t a) {
384         return (a + 7) & ~size_t(7);
385     }
386 };
387 static_assert(sizeof(Class) == 24, "Class structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
388 
389 struct TemplateObject
390 {
391     quint32_le size;
392 
calculateSizeTemplateObject393     static int calculateSize(int size) {
394         int trailingData = 2 * size * sizeof(quint32_le);
395         size_t s = align(sizeof(TemplateObject) + trailingData);
396         Q_ASSERT(s < INT_MAX);
397         return int(s);
398     }
399 
alignTemplateObject400     static size_t align(size_t a) {
401         return (a + 7) & ~size_t(7);
402     }
403 
stringTableTemplateObject404     const quint32_le *stringTable() const {
405         return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
406     }
407 
stringIndexAtTemplateObject408     uint stringIndexAt(uint i) const {
409         return stringTable()[i];
410     }
rawStringIndexAtTemplateObject411     uint rawStringIndexAt(uint i) const {
412         return stringTable()[size + i];
413     }
414 };
415 static_assert(sizeof(TemplateObject) == 4, "Template object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
416 
417 struct ExportEntry
418 {
419     quint32_le exportName;
420     quint32_le moduleRequest;
421     quint32_le importName;
422     quint32_le localName;
423     Location location;
424 };
425 static_assert(sizeof(ExportEntry) == 20, "ExportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
426 
427 struct ImportEntry
428 {
429     quint32_le moduleRequest;
430     quint32_le importName;
431     quint32_le localName;
432     Location location;
433 };
434 static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
435 
436 // Qml data structures
437 
438 struct TranslationData
439 {
440     quint32_le stringIndex;
441     quint32_le commentIndex;
442     qint32_le number;
443     quint32_le padding;
444 };
445 static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
446 
447 struct Binding
448 {
449     quint32_le propertyNameIndex;
450 
451     enum ValueType : unsigned int {
452         Type_Invalid,
453         Type_Boolean,
454         Type_Number,
455         Type_String,
456         Type_Null,
457         Type_Translation,
458         Type_TranslationById,
459         Type_Script,
460         Type_Object,
461         Type_AttachedProperty,
462         Type_GroupProperty
463     };
464 
465     enum Flags : unsigned int {
466         IsSignalHandlerExpression = 0x1,
467         IsSignalHandlerObject = 0x2,
468         IsOnAssignment = 0x4,
469         InitializerForReadOnlyDeclaration = 0x8,
470         IsResolvedEnum = 0x10,
471         IsListItem = 0x20,
472         IsBindingToAlias = 0x40,
473         IsDeferredBinding = 0x80,
474         IsCustomParserBinding = 0x100,
475         IsFunctionExpression = 0x200
476     };
477 
478     union {
479         quint32_le_bitfield<0, 16> flags;
480         quint32_le_bitfield<16, 16> type;
481     };
482     union {
483         bool b;
484         quint32_le constantValueIndex;
485         quint32_le compiledScriptIndex; // used when Type_Script
486         quint32_le objectIndex;
487         quint32_le translationDataIndex; // used when Type_Translation
488         quint32 nullMarker;
489     } value;
490     quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
491 
492     Location location;
493     Location valueLocation;
494 
isValueBindingBinding495     bool isValueBinding() const
496     {
497         if (type == Type_AttachedProperty
498             || type == Type_GroupProperty)
499             return false;
500         if (flags & IsSignalHandlerExpression
501             || flags & IsSignalHandlerObject)
502             return false;
503         return true;
504     }
505 
isValueBindingNoAliasBinding506     bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
isValueBindingToAliasBinding507     bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
508 
isSignalHandlerBinding509     bool isSignalHandler() const
510     {
511         if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
512             Q_ASSERT(!isValueBinding());
513             Q_ASSERT(!isAttachedProperty());
514             Q_ASSERT(!isGroupProperty());
515             return true;
516         }
517         return false;
518     }
519 
isAttachedPropertyBinding520     bool isAttachedProperty() const
521     {
522         if (type == Type_AttachedProperty) {
523             Q_ASSERT(!isValueBinding());
524             Q_ASSERT(!isSignalHandler());
525             Q_ASSERT(!isGroupProperty());
526             return true;
527         }
528         return false;
529     }
530 
isGroupPropertyBinding531     bool isGroupProperty() const
532     {
533         if (type == Type_GroupProperty) {
534             Q_ASSERT(!isValueBinding());
535             Q_ASSERT(!isSignalHandler());
536             Q_ASSERT(!isAttachedProperty());
537             return true;
538         }
539         return false;
540     }
541 
isFunctionExpressionBinding542     bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
543 
544     //reverse of Lexer::singleEscape()
escapedStringBinding545     static QString escapedString(const QString &string)
546     {
547         QString tmp = QLatin1String("\"");
548         for (int i = 0; i < string.length(); ++i) {
549             const QChar &c = string.at(i);
550             switch (c.unicode()) {
551             case 0x08:
552                 tmp += QLatin1String("\\b");
553                 break;
554             case 0x09:
555                 tmp += QLatin1String("\\t");
556                 break;
557             case 0x0A:
558                 tmp += QLatin1String("\\n");
559                 break;
560             case 0x0B:
561                 tmp += QLatin1String("\\v");
562                 break;
563             case 0x0C:
564                 tmp += QLatin1String("\\f");
565                 break;
566             case 0x0D:
567                 tmp += QLatin1String("\\r");
568                 break;
569             case 0x22:
570                 tmp += QLatin1String("\\\"");
571                 break;
572             case 0x27:
573                 tmp += QLatin1String("\\\'");
574                 break;
575             case 0x5C:
576                 tmp += QLatin1String("\\\\");
577                 break;
578             default:
579                 tmp += c;
580                 break;
581             }
582         }
583         tmp += QLatin1Char('\"');
584         return tmp;
585     }
586 
isTranslationBindingBinding587     bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
evaluatesToStringBinding588     bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
589 
valueAsBooleanBinding590     bool valueAsBoolean() const
591     {
592         if (type == Type_Boolean)
593             return value.b;
594         return false;
595     }
596 
597 };
598 
599 static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
600 
601 struct InlineComponent
602 {
603     quint32_le objectIndex;
604     quint32_le nameIndex;
605     Location location;
606 };
607 
608 static_assert(sizeof(InlineComponent) == 12, "InlineComponent structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
609 
610 struct EnumValue
611 {
612     quint32_le nameIndex;
613     qint32_le value;
614     Location location;
615 };
616 static_assert(sizeof(EnumValue) == 12, "EnumValue structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
617 
618 struct Enum
619 {
620     quint32_le nameIndex;
621     quint32_le nEnumValues;
622     Location location;
623 
enumValueAtEnum624     const EnumValue *enumValueAt(int idx) const {
625         return reinterpret_cast<const EnumValue*>(this + 1) + idx;
626     }
627 
calculateSizeEnum628     static int calculateSize(int nEnumValues) {
629         return (sizeof(Enum)
630                 + nEnumValues * sizeof(EnumValue)
631                 + 7) & ~0x7;
632     }
633 
634     // --- QQmlPropertyCacheCreatorInterface
enumValuesBeginEnum635     const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
enumValuesEndEnum636     const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
enumValueCountEnum637     int enumValueCount() const { return nEnumValues; }
638     // ---
639 };
640 static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
641 
642 struct Signal
643 {
644     quint32_le nameIndex;
645     quint32_le nParameters;
646     Location location;
647     // Parameter parameters[1];
648 
parameterAtSignal649     const Parameter *parameterAt(int idx) const {
650         return reinterpret_cast<const Parameter*>(this + 1) + idx;
651     }
652 
calculateSizeSignal653     static int calculateSize(int nParameters) {
654         return (sizeof(Signal)
655                 + nParameters * sizeof(Parameter)
656                 + 7) & ~0x7;
657     }
658 
659     // --- QQmlPropertyCacheCceatorInterface
parametersBeginSignal660     const Parameter *parametersBegin() const { return parameterAt(0); }
parametersEndSignal661     const Parameter *parametersEnd() const { return parameterAt(nParameters); }
parameterCountSignal662     int parameterCount() const { return nParameters; }
663     // ---
664 };
665 static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
666 
667 struct Property
668 {
669     quint32_le nameIndex;
670     union {
671         quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex;
672         quint32_le_bitfield<28, 1> isRequired;
673         quint32_le_bitfield<29, 1> isBuiltinType;
674         quint32_le_bitfield<30, 1> isList;
675         quint32_le_bitfield<31, 1> isReadOnly;
676     };
677 
678     Location location;
679 
setBuiltinTypeProperty680     void setBuiltinType(BuiltinType t)
681     {
682         builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
683         isBuiltinType = true;
684     }
builtinTypeProperty685     BuiltinType builtinType() const {
686         if (isBuiltinType)
687             return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
688         return BuiltinType::InvalidBuiltin;
689     }
setCustomTypeProperty690     void setCustomType(int nameIndex)
691     {
692         builtinTypeOrTypeNameIndex = nameIndex;
693         isBuiltinType = false;
694     }
695 };
696 static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
697 
698 struct RequiredPropertyExtraData {
699     quint32_le nameIndex;
700 };
701 
702 static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
703 
704 struct Alias {
705     enum Flags : unsigned int {
706         IsReadOnly = 0x1,
707         Resolved = 0x2,
708         AliasPointsToPointerObject = 0x4
709     };
710     union {
711         quint32_le_bitfield<0, 29> nameIndex;
712         quint32_le_bitfield<29, 3> flags;
713     };
714     union {
715         quint32_le idIndex; // string index
716         quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
717         quint32_le_bitfield<31, 1> aliasToLocalAlias;
718     };
719     union {
720         quint32_le propertyNameIndex; // string index
721         qint32_le encodedMetaPropertyIndex;
722         quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
723     };
724     Location location;
725     Location referenceLocation;
726 
isObjectAliasAlias727     bool isObjectAlias() const {
728         Q_ASSERT(flags & Resolved);
729         return encodedMetaPropertyIndex == -1;
730     }
731 };
732 static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
733 
734 struct Object
735 {
736     enum Flags : unsigned int {
737         NoFlag = 0x0,
738         IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
739         HasDeferredBindings = 0x2, // any of the bindings are deferred
740         HasCustomParserBindings = 0x4,
741         IsInlineComponentRoot = 0x8,
742         InPartOfInlineComponent = 0x10
743     };
744 
745     // Depending on the use, this may be the type name to instantiate before instantiating this
746     // object. For grouped properties the type name will be empty and for attached properties
747     // it will be the name of the attached type.
748     quint32_le inheritedTypeNameIndex;
749     quint32_le idNameIndex;
750     union {
751         quint32_le_bitfield<0, 15> flags;
752         quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
753         qint32_le_bitfield<16, 16> id;
754     };
755     qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
756     quint16_le nFunctions;
757     quint16_le nProperties;
758     quint32_le offsetToFunctions;
759     quint32_le offsetToProperties;
760     quint32_le offsetToAliases;
761     quint16_le nAliases;
762     quint16_le nEnums;
763     quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
764     quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
765     quint16_le nSignals;
766     quint16_le nBindings;
767     quint32_le offsetToBindings;
768     quint32_le nNamedObjectsInComponent;
769     quint32_le offsetToNamedObjectsInComponent;
770     Location location;
771     Location locationOfIdProperty;
772     quint32_le offsetToInlineComponents;
773     quint16_le nInlineComponents;
774     quint32_le offsetToRequiredPropertyExtraData;
775     quint16_le nRequiredPropertyExtraData;
776 //    Function[]
777 //    Property[]
778 //    Signal[]
779 //    Binding[]
780 //    InlineComponent[]
781 //    RequiredPropertyExtraData[]
782 
calculateSizeExcludingSignalsAndEnumsObject783     static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
784     {
785         return ( sizeof(Object)
786                  + nFunctions * sizeof(quint32)
787                  + nProperties * sizeof(Property)
788                  + nAliases * sizeof(Alias)
789                  + nEnums * sizeof(quint32)
790                  + nSignals * sizeof(quint32)
791                  + nBindings * sizeof(Binding)
792                  + nNamedObjectsInComponent * sizeof(int)
793                  + nInlineComponents * sizeof(InlineComponent)
794                  + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
795                  + 0x7
796                ) & ~0x7;
797     }
798 
functionOffsetTableObject799     const quint32_le *functionOffsetTable() const
800     {
801         return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
802     }
803 
propertyTableObject804     const Property *propertyTable() const
805     {
806         return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
807     }
808 
aliasTableObject809     const Alias *aliasTable() const
810     {
811         return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
812     }
813 
bindingTableObject814     const Binding *bindingTable() const
815     {
816         return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
817     }
818 
enumAtObject819     const Enum *enumAt(int idx) const
820     {
821         const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
822         const quint32_le offset = offsetTable[idx];
823         return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
824     }
825 
signalAtObject826     const Signal *signalAt(int idx) const
827     {
828         const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
829         const quint32_le offset = offsetTable[idx];
830         return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
831     }
832 
inlineComponentAtObject833     const InlineComponent *inlineComponentAt(int idx) const
834     {
835         return inlineComponentTable() + idx;
836     }
837 
namedObjectsInComponentTableObject838     const quint32_le *namedObjectsInComponentTable() const
839     {
840         return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
841     }
842 
inlineComponentTableObject843     const InlineComponent *inlineComponentTable() const
844     {
845         return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
846     }
847 
requiredPropertyExtraDataAtObject848     const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const
849     {
850         return requiredPropertyExtraDataTable() + idx;
851     }
852 
requiredPropertyExtraDataTableObject853     const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const
854     {
855         return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
856     }
857 
858     // --- QQmlPropertyCacheCreator interface
propertyCountObject859     int propertyCount() const { return nProperties; }
aliasCountObject860     int aliasCount() const { return nAliases; }
enumCountObject861     int enumCount() const { return nEnums; }
signalCountObject862     int signalCount() const { return nSignals; }
functionCountObject863     int functionCount() const { return nFunctions; }
864 
bindingsBeginObject865     const Binding *bindingsBegin() const { return bindingTable(); }
bindingsEndObject866     const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
867 
propertiesBeginObject868     const Property *propertiesBegin() const { return propertyTable(); }
propertiesEndObject869     const Property *propertiesEnd() const { return propertyTable() + nProperties; }
870 
aliasesBeginObject871     const Alias *aliasesBegin() const { return aliasTable(); }
aliasesEndObject872     const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
873 
874     typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator;
enumsBeginObject875     EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
enumsEndObject876     EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
877 
878     typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
signalsBeginObject879     SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
signalsEndObject880     SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
881 
882     typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator;
inlineComponentsBeginObject883     InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
inlineComponentsEndObject884     InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
885 
886     typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator;
requiredPropertyExtraDataBeginObject887     RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); };
requiredPropertyExtraDataEndObject888     RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); };
889 
namedObjectsInComponentCountObject890     int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
891     // ---
892 };
893 static_assert(sizeof(Object) == 84, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
894 
895 struct Import
896 {
897     enum ImportType : unsigned int {
898         ImportLibrary = 0x1,
899         ImportFile = 0x2,
900         ImportScript = 0x3,
901         ImportInlineComponent = 0x4
902     };
903     quint32_le type;
904 
905     quint32_le uriIndex;
906     quint32_le qualifierIndex;
907 
908     qint32_le majorVersion;
909     qint32_le minorVersion;
910 
911     Location location;
912 
ImportImport913     Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
914 };
915 static_assert(sizeof(Import) == 24, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
916 
917 struct QmlUnit
918 {
919     quint32_le nImports;
920     quint32_le offsetToImports;
921     quint32_le nObjects;
922     quint32_le offsetToObjects;
923 
importAtQmlUnit924     const Import *importAt(int idx) const {
925         return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
926     }
927 
objectAtQmlUnit928     const Object *objectAt(int idx) const {
929         const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
930         const quint32_le offset = offsetTable[idx];
931         return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
932     }
933 };
934 static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
935 
936 enum { QmlCompileHashSpace = 48 };
937 static const char magic_str[] = "qv4cdata";
938 
939 struct Unit
940 {
941     // DO NOT CHANGE THESE FIELDS EVER
942     char magic[8];
943     quint32_le version;
944     quint32_le qtVersion;
945     qint64_le sourceTimeStamp;
946     quint32_le unitSize; // Size of the Unit and any depending data.
947     // END DO NOT CHANGE THESE FIELDS EVER
948 
949     char libraryVersionHash[QmlCompileHashSpace];
950 
951     char md5Checksum[16]; // checksum of all bytes following this field.
952     char dependencyMD5Checksum[16];
953 
954     enum : unsigned int {
955         IsJavascript = 0x1,
956         StaticData = 0x2, // Unit data persistent in memory?
957         IsSingleton = 0x4,
958         IsSharedLibrary = 0x8, // .pragma shared?
959         IsESModule = 0x10,
960         PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation
961     };
962     quint32_le flags;
963     quint32_le stringTableSize;
964     quint32_le offsetToStringTable;
965     quint32_le functionTableSize;
966     quint32_le offsetToFunctionTable;
967     quint32_le classTableSize;
968     quint32_le offsetToClassTable;
969     quint32_le templateObjectTableSize;
970     quint32_le offsetToTemplateObjectTable;
971     quint32_le blockTableSize;
972     quint32_le offsetToBlockTable;
973     quint32_le lookupTableSize;
974     quint32_le offsetToLookupTable;
975     quint32_le regexpTableSize;
976     quint32_le offsetToRegexpTable;
977     quint32_le constantTableSize;
978     quint32_le offsetToConstantTable;
979     quint32_le jsClassTableSize;
980     quint32_le offsetToJSClassTable;
981     quint32_le translationTableSize;
982     quint32_le offsetToTranslationTable;
983     quint32_le localExportEntryTableSize;
984     quint32_le offsetToLocalExportEntryTable;
985     quint32_le indirectExportEntryTableSize;
986     quint32_le offsetToIndirectExportEntryTable;
987     quint32_le starExportEntryTableSize;
988     quint32_le offsetToStarExportEntryTable;
989     quint32_le importEntryTableSize;
990     quint32_le offsetToImportEntryTable;
991     quint32_le moduleRequestTableSize;
992     quint32_le offsetToModuleRequestTable;
993     qint32_le indexOfRootFunction;
994     quint32_le sourceFileIndex;
995     quint32_le finalUrlIndex;
996 
997     quint32_le offsetToQmlUnit;
998 
999     /* QML specific fields */
1000 
qmlUnitUnit1001     const QmlUnit *qmlUnit() const {
1002         return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
1003     }
1004 
qmlUnitUnit1005     QmlUnit *qmlUnit() {
1006         return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
1007     }
1008 
isSingletonUnit1009     bool isSingleton() const {
1010         return flags & Unit::IsSingleton;
1011     }
1012     /* end QML specific fields*/
1013 
stringAtInternalUnit1014     QString stringAtInternal(int idx) const {
1015         Q_ASSERT(idx < int(stringTableSize));
1016         const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
1017         const quint32_le offset = offsetTable[idx];
1018         const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
1019         if (str->size == 0)
1020             return QString();
1021 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1022         if (flags & StaticData) {
1023             const QStringDataPtr holder = { const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) };
1024             return QString(holder);
1025         }
1026         const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
1027         return QString(characters, str->size);
1028 #else
1029         const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
1030         QString qstr(str->size, Qt::Uninitialized);
1031         QChar *ch = qstr.data();
1032         for (int i = 0; i < str->size; ++i)
1033              ch[i] = QChar(characters[i]);
1034          return qstr;
1035 #endif
1036     }
1037 
functionOffsetTableUnit1038     const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
classOffsetTableUnit1039     const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
templateObjectOffsetTableUnit1040     const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
blockOffsetTableUnit1041     const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
1042 
functionAtUnit1043     const Function *functionAt(int idx) const {
1044         const quint32_le *offsetTable = functionOffsetTable();
1045         const quint32_le offset = offsetTable[idx];
1046         return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
1047     }
1048 
classAtUnit1049     const Class *classAt(int idx) const {
1050         const quint32_le *offsetTable = classOffsetTable();
1051         const quint32_le offset = offsetTable[idx];
1052         return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
1053     }
1054 
templateObjectAtUnit1055     const TemplateObject *templateObjectAt(int idx) const {
1056         const quint32_le *offsetTable = templateObjectOffsetTable();
1057         const quint32_le offset = offsetTable[idx];
1058         return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
1059     }
1060 
blockAtUnit1061     const Block *blockAt(int idx) const {
1062         const quint32_le *offsetTable = blockOffsetTable();
1063         const quint32_le offset = offsetTable[idx];
1064         return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
1065     }
1066 
lookupTableUnit1067     const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
regexpAtUnit1068     const RegExp *regexpAt(int index) const {
1069         return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
1070     }
constantsUnit1071     const quint64_le *constants() const {
1072         return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
1073     }
1074 
jsClassAtUnit1075     const JSClassMember *jsClassAt(int idx, int *nMembers) const {
1076         const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
1077         const quint32_le offset = offsetTable[idx];
1078         const char *ptr = reinterpret_cast<const char *>(this) + offset;
1079         const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
1080         *nMembers = klass->nMembers;
1081         return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
1082     }
1083 
translationsUnit1084     const TranslationData *translations() const {
1085         return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
1086     }
1087 
importEntryTableUnit1088     const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
localExportEntryTableUnit1089     const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
indirectExportEntryTableUnit1090     const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
starExportEntryTableUnit1091     const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
1092 
moduleRequestTableUnit1093     const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
1094 };
1095 
1096 static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
1097 
1098 struct TypeReference
1099 {
TypeReferenceTypeReference1100     TypeReference(const Location &loc)
1101         : location(loc)
1102         , needsCreation(false)
1103         , errorWhenNotFound(false)
1104     {}
1105     Location location; // first use
1106     bool needsCreation : 1; // whether the type needs to be creatable or not
1107     bool errorWhenNotFound: 1;
1108 };
1109 
1110 // Map from name index to location of first use.
1111 struct TypeReferenceMap : QHash<int, TypeReference>
1112 {
addTypeReferenceMap1113     TypeReference &add(int nameIndex, const Location &loc) {
1114         Iterator it = find(nameIndex);
1115         if (it != end())
1116             return *it;
1117         return *insert(nameIndex, loc);
1118     }
1119 
1120     template <typename CompiledObject>
collectFromObjectTypeReferenceMap1121     void collectFromObject(const CompiledObject *obj)
1122     {
1123         if (obj->inheritedTypeNameIndex != 0) {
1124             TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
1125             r.needsCreation = true;
1126             r.errorWhenNotFound = true;
1127         }
1128 
1129         auto prop = obj->propertiesBegin();
1130         auto const propEnd = obj->propertiesEnd();
1131         for ( ; prop != propEnd; ++prop) {
1132             if (!prop->isBuiltinType) {
1133                 TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
1134                 r.errorWhenNotFound = true;
1135             }
1136         }
1137 
1138         auto binding = obj->bindingsBegin();
1139         auto const bindingEnd = obj->bindingsEnd();
1140         for ( ; binding != bindingEnd; ++binding) {
1141             if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
1142                 this->add(binding->propertyNameIndex, binding->location);
1143         }
1144 
1145         auto ic = obj->inlineComponentsBegin();
1146         auto const icEnd = obj->inlineComponentsEnd();
1147         for (; ic != icEnd; ++ic) {
1148             this->add(ic->nameIndex, ic->location);
1149         }
1150     }
1151 
1152     template <typename Iterator>
collectFromObjectsTypeReferenceMap1153     void collectFromObjects(Iterator it, Iterator end)
1154     {
1155         for (; it != end; ++it)
1156             collectFromObject(*it);
1157     }
1158 };
1159 
1160 using DependentTypesHasher = std::function<QByteArray()>;
1161 
1162 // This is how this hooks into the existing structures:
1163 
1164 struct CompilationUnitBase
1165 {
1166     Q_DISABLE_COPY(CompilationUnitBase)
1167 
1168     CompilationUnitBase() = default;
1169     ~CompilationUnitBase() = default;
1170 
CompilationUnitBaseCompilationUnitBase1171     CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); }
1172 
1173     CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept
1174     {
1175         if (this != &other) {
1176             runtimeStrings = other.runtimeStrings;
1177             other.runtimeStrings = nullptr;
1178             constants = other.constants;
1179             other.constants = nullptr;
1180             runtimeRegularExpressions = other.runtimeRegularExpressions;
1181             other.runtimeRegularExpressions = nullptr;
1182             runtimeClasses = other.runtimeClasses;
1183             other.runtimeClasses = nullptr;
1184             imports = other.imports;
1185             other.imports = nullptr;
1186         }
1187         return *this;
1188     }
1189 
1190     // pointers either to data->constants() or little-endian memory copy.
1191     Heap::String **runtimeStrings = nullptr; // Array
1192     const StaticValue* constants = nullptr;
1193     QV4::StaticValue *runtimeRegularExpressions = nullptr;
1194     Heap::InternalClass **runtimeClasses = nullptr;
1195     const StaticValue** imports = nullptr;
1196 };
1197 
1198 Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
1199 Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
1200 Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
1201 Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
1202 Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
1203 Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
1204 
1205 struct CompilationUnit : public CompilationUnitBase
1206 {
1207     Q_DISABLE_COPY(CompilationUnit)
1208 
1209     const Unit *data = nullptr;
1210     const QmlUnit *qmlData = nullptr;
1211     QStringList dynamicStrings;
1212 public:
1213     using CompiledObject = CompiledData::Object;
1214 
1215     CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(),
1216                     const QString &finalUrlString = QString())
1217     {
1218         setUnitData(unitData, nullptr, fileName, finalUrlString);
1219     }
1220 
~CompilationUnitCompilationUnit1221     ~CompilationUnit()
1222     {
1223         if (data) {
1224             if (data->qmlUnit() != qmlData)
1225                 free(const_cast<QmlUnit *>(qmlData));
1226             qmlData = nullptr;
1227 
1228             if (!(data->flags & QV4::CompiledData::Unit::StaticData))
1229                 free(const_cast<Unit *>(data));
1230         }
1231         data = nullptr;
1232 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
1233         delete [] constants;
1234         constants = nullptr;
1235 #endif
1236 
1237         delete [] imports;
1238         imports = nullptr;
1239     }
1240 
CompilationUnitCompilationUnit1241     CompilationUnit(CompilationUnit &&other) noexcept
1242     {
1243         *this = std::move(other);
1244     }
1245 
1246     CompilationUnit &operator=(CompilationUnit &&other) noexcept
1247     {
1248         if (this != &other) {
1249             data = other.data;
1250             other.data = nullptr;
1251             qmlData = other.qmlData;
1252             other.qmlData = nullptr;
1253             dynamicStrings = std::move(other.dynamicStrings);
1254             other.dynamicStrings.clear();
1255             m_fileName = std::move(other.m_fileName);
1256             other.m_fileName.clear();
1257             m_finalUrlString = std::move(other.m_finalUrlString);
1258             other.m_finalUrlString.clear();
1259             m_module = other.m_module;
1260             other.m_module = nullptr;
1261             CompilationUnitBase::operator=(std::move(other));
1262         }
1263         return *this;
1264     }
1265 
unitDataCompilationUnit1266     const Unit *unitData() const { return data; }
1267 
1268     void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
1269                      const QString &fileName = QString(), const QString &finalUrlString = QString())
1270     {
1271         data = unitData;
1272         qmlData = nullptr;
1273 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
1274         delete [] constants;
1275 #endif
1276         constants = nullptr;
1277         m_fileName.clear();
1278         m_finalUrlString.clear();
1279         if (!data)
1280             return;
1281 
1282         qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
1283 
1284 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
1285         StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
1286         const quint64_le *littleEndianConstants = data->constants();
1287         for (uint i = 0; i < data->constantTableSize; ++i)
1288             bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
1289         constants = bigEndianConstants;
1290 #else
1291         constants = reinterpret_cast<const StaticValue*>(data->constants());
1292 #endif
1293 
1294         m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
1295         m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
1296     }
1297 
stringAtCompilationUnit1298     QString stringAt(int index) const
1299     {
1300         if (uint(index) >= data->stringTableSize)
1301             return dynamicStrings.at(index - data->stringTableSize);
1302         return data->stringAtInternal(index);
1303     }
1304 
fileNameCompilationUnit1305     QString fileName() const { return m_fileName; }
finalUrlStringCompilationUnit1306     QString finalUrlString() const { return m_finalUrlString; }
1307 
moduleCompilationUnit1308     Heap::Module *module() const { return m_module; }
setModuleCompilationUnit1309     void setModule(Heap::Module *module) { m_module = module; }
1310 
1311 private:
1312     QString m_fileName; // initialized from data->sourceFileIndex
1313     QString m_finalUrlString; // initialized from data->finalUrlIndex
1314 
1315     Heap::Module *m_module = nullptr;
1316 };
1317 
1318 class SaveableUnitPointer
1319 {
Q_DISABLE_COPY_MOVE(SaveableUnitPointer)1320     Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
1321 public:
1322     SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) :
1323           unit(unit),
1324           temporaryFlags(temporaryFlags)
1325     {
1326     }
1327 
1328     ~SaveableUnitPointer() = default;
1329 
1330     template<typename Char>
saveToDisk(const std::function<bool (const Char *,quint32)> & writer)1331     bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
1332     {
1333         auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; });
1334         mutableFlags() |= temporaryFlags;
1335         return writer(data<Char>(), size());
1336     }
1337 
writeDataToFile(const QString & outputFileName,const char * data,quint32 size,QString * errorString)1338     static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
1339                                 QString *errorString)
1340     {
1341 #if QT_CONFIG(temporaryfile)
1342         QSaveFile cacheFile(outputFileName);
1343         if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
1344                 || cacheFile.write(data, size) != size
1345                 || !cacheFile.commit()) {
1346             *errorString = cacheFile.errorString();
1347             return false;
1348         }
1349 
1350         errorString->clear();
1351         return true;
1352 #else
1353         Q_UNUSED(outputFileName)
1354         *errorString = QStringLiteral("features.temporaryfile is disabled.");
1355         return false;
1356 #endif
1357     }
1358 
1359 private:
1360     const Unit *unit;
1361     quint32 temporaryFlags;
1362 
mutableFlags()1363     quint32_le &mutableFlags() const
1364     {
1365         return const_cast<Unit *>(unit)->flags;
1366     }
1367 
1368     template<typename Char>
data()1369     const Char *data() const
1370     {
1371         Q_STATIC_ASSERT(sizeof(Char) == 1);
1372         const Char *dataPtr;
1373         memcpy(&dataPtr, &unit, sizeof(dataPtr));
1374         return dataPtr;
1375     }
1376 
size()1377     quint32 size() const
1378     {
1379         return unit->unitSize;
1380     }
1381 };
1382 
1383 
1384 } // CompiledData namespace
1385 } // QV4 namespace
1386 
1387 Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
1388 
1389 QT_END_NAMESPACE
1390 
1391 #endif
1392