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
69QT_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
80class QIODevice;
81class QQmlTypeNameCache;
82class QQmlType;
83class QQmlEngine;
84
85namespace QmlIR {
86struct Document;
87}
88
89namespace QV4 {
90namespace Heap {
91struct Module;
92struct String;
93struct InternalClass;
94};
95
96struct Function;
97class EvalISelFactory;
98
99namespace CompiledData {
100
101struct String;
102struct Function;
103struct Lookup;
104struct RegExp;
105struct Unit;
106
107template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
108struct TableIterator
109{
110 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
121struct Location
122{
123 union {
124 quint32 _dummy;
125 quint32_le_bitfield<0, 20> line;
126 quint32_le_bitfield<20, 12> column;
127 };
128
129 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};
136static_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
138struct 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
154 RegExp() : _dummy(0) { }
155};
156static_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
158struct 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
173 Lookup() : _dummy(0) { }
174};
175static_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
177struct JSClassMember
178{
179 union {
180 quint32 _dummy;
181 quint32_le_bitfield<0, 31> nameOffset;
182 quint32_le_bitfield<31, 1> isAccessor;
183 };
184
185 JSClassMember() : _dummy(0) { }
186};
187static_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
189struct JSClass
190{
191 quint32_le nMembers;
192 // JSClassMember[nMembers]
193
194 static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
195};
196static_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.
206struct 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
215 static int calculateSize(const QString &str) {
216 return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
217 }
218};
219static_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
222static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location");
223static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location");
224static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location");
225static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location");
226#if QT_POINTER_SIZE == 8
227static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location");
228#else
229static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location");
230#endif
231
232struct CodeOffsetToLine {
233 quint32_le codeOffset;
234 quint32_le line;
235};
236static_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
238struct Block
239{
240 quint32_le nLocals;
241 quint32_le localsOffset;
242 quint16_le sizeOfLocalTemporalDeadZone;
243 quint16_le padding;
244
245 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
246
247 static int calculateSize(int nLocals) {
248 int trailingData = nLocals*sizeof (quint32);
249 size_t size = align(a: align(a: sizeof(Block)) + size_t(trailingData));
250 Q_ASSERT(size < INT_MAX);
251 return int(size);
252 }
253
254 static size_t align(size_t a) {
255 return (a + 7) & ~size_t(7);
256 }
257};
258static_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
260enum 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
266struct ParameterType
267{
268 union {
269 quint32 _dummy;
270 quint32_le_bitfield<0, 1> indexIsBuiltinType;
271 quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
272 };
273};
274static_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
276struct Parameter
277{
278 quint32_le nameIndex;
279 ParameterType type;
280};
281static_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.
285struct 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;
305 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
316 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
325 const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); }
326 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
327 const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
328
329 // --- QQmlPropertyCacheCreator interface
330 const Parameter *formalsBegin() const { return formalsTable(); }
331 const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
332 // ---
333
334 const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
335
336 const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
337
338 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(a: align(a: sizeof(Function)) + size_t(trailingData)) + align(a: codeSize);
342 Q_ASSERT(size < INT_MAX);
343 return int(size);
344 }
345
346 static size_t align(size_t a) {
347 return (a + 7) & ~size_t(7);
348 }
349};
350static_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
352struct 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};
363static_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
365struct 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
374 const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
375
376 static int calculateSize(int nStaticMethods, int nMethods) {
377 int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
378 size_t size = align(a: sizeof(Class) + trailingData);
379 Q_ASSERT(size < INT_MAX);
380 return int(size);
381 }
382
383 static size_t align(size_t a) {
384 return (a + 7) & ~size_t(7);
385 }
386};
387static_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
389struct TemplateObject
390{
391 quint32_le size;
392
393 static int calculateSize(int size) {
394 int trailingData = 2 * size * sizeof(quint32_le);
395 size_t s = align(a: sizeof(TemplateObject) + trailingData);
396 Q_ASSERT(s < INT_MAX);
397 return int(s);
398 }
399
400 static size_t align(size_t a) {
401 return (a + 7) & ~size_t(7);
402 }
403
404 const quint32_le *stringTable() const {
405 return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
406 }
407
408 uint stringIndexAt(uint i) const {
409 return stringTable()[i];
410 }
411 uint rawStringIndexAt(uint i) const {
412 return stringTable()[size + i];
413 }
414};
415static_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
417struct ExportEntry
418{
419 quint32_le exportName;
420 quint32_le moduleRequest;
421 quint32_le importName;
422 quint32_le localName;
423 Location location;
424};
425static_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
427struct ImportEntry
428{
429 quint32_le moduleRequest;
430 quint32_le importName;
431 quint32_le localName;
432 Location location;
433};
434static_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
438struct TranslationData
439{
440 quint32_le stringIndex;
441 quint32_le commentIndex;
442 qint32_le number;
443 quint32_le padding;
444};
445static_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
447struct 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
495 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
506 bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
507 bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
508
509 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
520 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
531 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
542 bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
543
544 //reverse of Lexer::singleEscape()
545 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
587 bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
588 bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
589
590 bool valueAsBoolean() const
591 {
592 if (type == Type_Boolean)
593 return value.b;
594 return false;
595 }
596
597};
598
599static_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
601struct InlineComponent
602{
603 quint32_le objectIndex;
604 quint32_le nameIndex;
605 Location location;
606};
607
608static_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
610struct EnumValue
611{
612 quint32_le nameIndex;
613 qint32_le value;
614 Location location;
615};
616static_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
618struct Enum
619{
620 quint32_le nameIndex;
621 quint32_le nEnumValues;
622 Location location;
623
624 const EnumValue *enumValueAt(int idx) const {
625 return reinterpret_cast<const EnumValue*>(this + 1) + idx;
626 }
627
628 static int calculateSize(int nEnumValues) {
629 return (sizeof(Enum)
630 + nEnumValues * sizeof(EnumValue)
631 + 7) & ~0x7;
632 }
633
634 // --- QQmlPropertyCacheCreatorInterface
635 const EnumValue *enumValuesBegin() const { return enumValueAt(idx: 0); }
636 const EnumValue *enumValuesEnd() const { return enumValueAt(idx: nEnumValues); }
637 int enumValueCount() const { return nEnumValues; }
638 // ---
639};
640static_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
642struct Signal
643{
644 quint32_le nameIndex;
645 quint32_le nParameters;
646 Location location;
647 // Parameter parameters[1];
648
649 const Parameter *parameterAt(int idx) const {
650 return reinterpret_cast<const Parameter*>(this + 1) + idx;
651 }
652
653 static int calculateSize(int nParameters) {
654 return (sizeof(Signal)
655 + nParameters * sizeof(Parameter)
656 + 7) & ~0x7;
657 }
658
659 // --- QQmlPropertyCacheCceatorInterface
660 const Parameter *parametersBegin() const { return parameterAt(idx: 0); }
661 const Parameter *parametersEnd() const { return parameterAt(idx: nParameters); }
662 int parameterCount() const { return nParameters; }
663 // ---
664};
665static_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
667struct 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
680 void setBuiltinType(BuiltinType t)
681 {
682 builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
683 isBuiltinType = true;
684 }
685 BuiltinType builtinType() const {
686 if (isBuiltinType)
687 return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
688 return BuiltinType::InvalidBuiltin;
689 }
690 void setCustomType(int nameIndex)
691 {
692 builtinTypeOrTypeNameIndex = nameIndex;
693 isBuiltinType = false;
694 }
695};
696static_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
698struct RequiredPropertyExtraData {
699 quint32_le nameIndex;
700};
701
702static_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
704struct 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
727 bool isObjectAlias() const {
728 Q_ASSERT(flags & Resolved);
729 return encodedMetaPropertyIndex == -1;
730 }
731};
732static_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
734struct 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
783 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
799 const quint32_le *functionOffsetTable() const
800 {
801 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
802 }
803
804 const Property *propertyTable() const
805 {
806 return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
807 }
808
809 const Alias *aliasTable() const
810 {
811 return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
812 }
813
814 const Binding *bindingTable() const
815 {
816 return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
817 }
818
819 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
826 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
833 const InlineComponent *inlineComponentAt(int idx) const
834 {
835 return inlineComponentTable() + idx;
836 }
837
838 const quint32_le *namedObjectsInComponentTable() const
839 {
840 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
841 }
842
843 const InlineComponent *inlineComponentTable() const
844 {
845 return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
846 }
847
848 const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const
849 {
850 return requiredPropertyExtraDataTable() + idx;
851 }
852
853 const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const
854 {
855 return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
856 }
857
858 // --- QQmlPropertyCacheCreator interface
859 int propertyCount() const { return nProperties; }
860 int aliasCount() const { return nAliases; }
861 int enumCount() const { return nEnums; }
862 int signalCount() const { return nSignals; }
863 int functionCount() const { return nFunctions; }
864
865 const Binding *bindingsBegin() const { return bindingTable(); }
866 const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
867
868 const Property *propertiesBegin() const { return propertyTable(); }
869 const Property *propertiesEnd() const { return propertyTable() + nProperties; }
870
871 const Alias *aliasesBegin() const { return aliasTable(); }
872 const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
873
874 typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator;
875 EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
876 EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
877
878 typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
879 SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
880 SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
881
882 typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator;
883 InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
884 InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
885
886 typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator;
887 RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); };
888 RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); };
889
890 int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
891 // ---
892};
893static_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
895struct 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
913 Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
914};
915static_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
917struct QmlUnit
918{
919 quint32_le nImports;
920 quint32_le offsetToImports;
921 quint32_le nObjects;
922 quint32_le offsetToObjects;
923
924 const Import *importAt(int idx) const {
925 return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
926 }
927
928 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};
934static_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
936enum { QmlCompileHashSpace = 48 };
937static const char magic_str[] = "qv4cdata";
938
939struct 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
1001 const QmlUnit *qmlUnit() const {
1002 return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
1003 }
1004
1005 QmlUnit *qmlUnit() {
1006 return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
1007 }
1008
1009 bool isSingleton() const {
1010 return flags & Unit::IsSingleton;
1011 }
1012 /* end QML specific fields*/
1013
1014 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 = { .ptr: 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
1038 const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
1039 const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
1040 const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
1041 const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
1042
1043 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
1049 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
1055 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
1061 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
1067 const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
1068 const RegExp *regexpAt(int index) const {
1069 return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
1070 }
1071 const quint64_le *constants() const {
1072 return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
1073 }
1074
1075 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
1084 const TranslationData *translations() const {
1085 return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
1086 }
1087
1088 const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
1089 const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
1090 const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
1091 const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
1092
1093 const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
1094};
1095
1096static_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
1098struct TypeReference
1099{
1100 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.
1111struct TypeReferenceMap : QHash<int, TypeReference>
1112{
1113 TypeReference &add(int nameIndex, const Location &loc) {
1114 Iterator it = find(akey: nameIndex);
1115 if (it != end())
1116 return *it;
1117 return *insert(akey: nameIndex, avalue: loc);
1118 }
1119
1120 template <typename CompiledObject>
1121 void collectFromObject(const CompiledObject *obj)
1122 {
1123 if (obj->inheritedTypeNameIndex != 0) {
1124 TypeReference &r = this->add(nameIndex: obj->inheritedTypeNameIndex, loc: 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(nameIndex: prop->builtinTypeOrTypeNameIndex, loc: 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(nameIndex: binding->propertyNameIndex, loc: binding->location);
1143 }
1144
1145 auto ic = obj->inlineComponentsBegin();
1146 auto const icEnd = obj->inlineComponentsEnd();
1147 for (; ic != icEnd; ++ic) {
1148 this->add(nameIndex: ic->nameIndex, loc: ic->location);
1149 }
1150 }
1151
1152 template <typename Iterator>
1153 void collectFromObjects(Iterator it, Iterator end)
1154 {
1155 for (; it != end; ++it)
1156 collectFromObject(*it);
1157 }
1158};
1159
1160using DependentTypesHasher = std::function<QByteArray()>;
1161
1162// This is how this hooks into the existing structures:
1163
1164struct CompilationUnitBase
1165{
1166 Q_DISABLE_COPY(CompilationUnitBase)
1167
1168 CompilationUnitBase() = default;
1169 ~CompilationUnitBase() = default;
1170
1171 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
1198Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
1199Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
1200Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
1201Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
1202Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
1203Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
1204
1205struct CompilationUnit : public CompilationUnitBase
1206{
1207 Q_DISABLE_COPY(CompilationUnit)
1208
1209 const Unit *data = nullptr;
1210 const QmlUnit *qmlData = nullptr;
1211 QStringList dynamicStrings;
1212public:
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, qmlUnit: nullptr, fileName, finalUrlString);
1219 }
1220
1221 ~CompilationUnit()
1222 {
1223 if (data) {
1224 if (data->qmlUnit() != qmlData)
1225 free(ptr: const_cast<QmlUnit *>(qmlData));
1226 qmlData = nullptr;
1227
1228 if (!(data->flags & QV4::CompiledData::Unit::StaticData))
1229 free(ptr: 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
1241 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=(other: std::move(other));
1262 }
1263 return *this;
1264 }
1265
1266 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(index: data->sourceFileIndex);
1295 m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(index: data->finalUrlIndex);
1296 }
1297
1298 QString stringAt(int index) const
1299 {
1300 if (uint(index) >= data->stringTableSize)
1301 return dynamicStrings.at(i: index - data->stringTableSize);
1302 return data->stringAtInternal(idx: index);
1303 }
1304
1305 QString fileName() const { return m_fileName; }
1306 QString finalUrlString() const { return m_finalUrlString; }
1307
1308 Heap::Module *module() const { return m_module; }
1309 void setModule(Heap::Module *module) { m_module = module; }
1310
1311private:
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
1318class SaveableUnitPointer
1319{
1320 Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
1321public:
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>
1331 bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
1332 {
1333 const quint32_le oldFlags = mutableFlags();
1334 auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
1335 mutableFlags() |= temporaryFlags;
1336 return writer(data<Char>(), size());
1337 }
1338
1339 static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
1340 QString *errorString)
1341 {
1342#if QT_CONFIG(temporaryfile)
1343 QSaveFile cacheFile(outputFileName);
1344 if (!cacheFile.open(flags: QIODevice::WriteOnly | QIODevice::Truncate)
1345 || cacheFile.write(data, len: size) != size
1346 || !cacheFile.commit()) {
1347 *errorString = cacheFile.errorString();
1348 return false;
1349 }
1350
1351 errorString->clear();
1352 return true;
1353#else
1354 Q_UNUSED(outputFileName)
1355 *errorString = QStringLiteral("features.temporaryfile is disabled.");
1356 return false;
1357#endif
1358 }
1359
1360private:
1361 const Unit *unit;
1362 quint32 temporaryFlags;
1363
1364 quint32_le &mutableFlags() const
1365 {
1366 return const_cast<Unit *>(unit)->flags;
1367 }
1368
1369 template<typename Char>
1370 const Char *data() const
1371 {
1372 Q_STATIC_ASSERT(sizeof(Char) == 1);
1373 const Char *dataPtr;
1374 memcpy(&dataPtr, &unit, sizeof(dataPtr));
1375 return dataPtr;
1376 }
1377
1378 quint32 size() const
1379 {
1380 return unit->unitSize;
1381 }
1382};
1383
1384
1385} // CompiledData namespace
1386} // QV4 namespace
1387
1388Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
1389
1390QT_END_NAMESPACE
1391
1392#endif
1393

source code of qtdeclarative/src/qml/common/qv4compileddata_p.h