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 0x24 // Collect function parameter types
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 void operator++() { ++index; }
116 bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
117 bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
118};
119
120struct Location
121{
122 union {
123 quint32 _dummy;
124 quint32_le_bitfield<0, 20> line;
125 quint32_le_bitfield<20, 12> column;
126 };
127
128 Location() : _dummy(0) { }
129
130 inline bool operator<(const Location &other) const {
131 return line < other.line ||
132 (line == other.line && column < other.column);
133 }
134};
135static_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");
136
137struct RegExp
138{
139 enum Flags : unsigned int {
140 RegExp_NoFlags = 0x0,
141 RegExp_Global = 0x01,
142 RegExp_IgnoreCase = 0x02,
143 RegExp_Multiline = 0x04,
144 RegExp_Unicode = 0x08,
145 RegExp_Sticky = 0x10
146 };
147 union {
148 quint32 _dummy;
149 quint32_le_bitfield<0, 5> flags;
150 quint32_le_bitfield<5, 27> stringIndex;
151 };
152
153 RegExp() : _dummy(0) { }
154};
155static_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");
156
157struct Lookup
158{
159 enum Type : unsigned int {
160 Type_Getter = 0,
161 Type_Setter = 1,
162 Type_GlobalGetter = 2,
163 Type_QmlContextPropertyGetter = 3
164 };
165
166 union {
167 quint32 _dummy;
168 quint32_le_bitfield<0, 4> type_and_flags;
169 quint32_le_bitfield<4, 28> nameIndex;
170 };
171
172 Lookup() : _dummy(0) { }
173};
174static_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");
175
176struct JSClassMember
177{
178 union {
179 quint32 _dummy;
180 quint32_le_bitfield<0, 31> nameOffset;
181 quint32_le_bitfield<31, 1> isAccessor;
182 };
183
184 JSClassMember() : _dummy(0) { }
185};
186static_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");
187
188struct JSClass
189{
190 quint32_le nMembers;
191 // JSClassMember[nMembers]
192
193 static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
194};
195static_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");
196
197// This data structure is intended to be binary compatible with QStringData/QStaticStringData on
198// 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped
199// from a file must be castable to a QStringData regardless of the pointer size. With the first
200// few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a
201// ptrdiff_t and thus variable in size.
202// On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while
203// on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain
204// the same value.
205struct String
206{
207 qint32_le refcount; // -1
208 qint32_le size;
209 quint32_le allocAndCapacityReservedFlag; // 0
210 quint32_le offsetOn32Bit;
211 quint64_le offsetOn64Bit;
212 // uint16 strdata[]
213
214 static int calculateSize(const QString &str) {
215 return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
216 }
217};
218static_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");
219
220// Ensure compatibility with QString
221static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location");
222static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location");
223static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location");
224static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location");
225#if QT_POINTER_SIZE == 8
226static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location");
227#else
228static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location");
229#endif
230
231struct CodeOffsetToLine {
232 quint32_le codeOffset;
233 quint32_le line;
234};
235static_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");
236
237struct Block
238{
239 quint32_le nLocals;
240 quint32_le localsOffset;
241 quint16_le sizeOfLocalTemporalDeadZone;
242 quint16_le padding;
243
244 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
245
246 static int calculateSize(int nLocals) {
247 int trailingData = nLocals*sizeof (quint32);
248 size_t size = align(align(sizeof(Block)) + size_t(trailingData));
249 Q_ASSERT(size < INT_MAX);
250 return int(size);
251 }
252
253 static size_t align(size_t a) {
254 return (a + 7) & ~size_t(7);
255 }
256};
257static_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");
258
259enum class BuiltinType : unsigned int {
260 Var = 0, Variant, Int, Bool, Real, String, Url, Color,
261 Font, Time, Date, DateTime, Rect, Point, Size,
262 Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin
263};
264
265struct ParameterType
266{
267 union {
268 quint32 _dummy;
269 quint32_le_bitfield<0, 1> indexIsBuiltinType;
270 quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
271 };
272};
273static_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");
274
275struct Parameter
276{
277 quint32_le nameIndex;
278 ParameterType type;
279};
280static_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");
281
282// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
283// for unaligned access. The ordering of the fields is also from largest to smallest.
284struct Function
285{
286 enum Flags : unsigned int {
287 IsStrict = 0x1,
288 IsArrowFunction = 0x2,
289 IsGenerator = 0x4
290 };
291
292 // Absolute offset into file where the code for this function is located.
293 quint32_le codeOffset;
294 quint32_le codeSize;
295
296 quint32_le nameIndex;
297 quint16_le length;
298 quint16_le nFormals;
299 quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
300 ParameterType returnType;
301 quint32_le localsOffset;
302 quint16_le nLocals;
303 quint16_le nLineNumbers;
304 size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
305 quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
306 quint16_le sizeOfLocalTemporalDeadZone;
307 quint16_le firstTemporalDeadZoneRegister;
308 quint16_le sizeOfRegisterTemporalDeadZone;
309 quint16_le nRegisters;
310 Location location;
311
312 quint32_le nLabelInfos;
313 size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
314
315 // Keep all unaligned data at the end
316 quint8 flags;
317 quint8 padding1;
318
319 // quint32 formalsIndex[nFormals]
320 // quint32 localsIndex[nLocals]
321
322 const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); }
323 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
324 const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
325
326 // --- QQmlPropertyCacheCreator interface
327 const Parameter *formalsBegin() const { return formalsTable(); }
328 const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
329 // ---
330
331 const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
332
333 const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
334
335 static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
336 int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
337 + nLines*sizeof(CodeOffsetToLine);
338 size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
339 Q_ASSERT(size < INT_MAX);
340 return int(size);
341 }
342
343 static size_t align(size_t a) {
344 return (a + 7) & ~size_t(7);
345 }
346};
347static_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");
348
349struct Method {
350 enum Type {
351 Regular,
352 Getter,
353 Setter
354 };
355
356 quint32_le name;
357 quint32_le type;
358 quint32_le function;
359};
360static_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");
361
362struct Class
363{
364 quint32_le nameIndex;
365 quint32_le scopeIndex;
366 quint32_le constructorFunction;
367 quint32_le nStaticMethods;
368 quint32_le nMethods;
369 quint32_le methodTableOffset;
370
371 const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
372
373 static int calculateSize(int nStaticMethods, int nMethods) {
374 int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
375 size_t size = align(sizeof(Class) + trailingData);
376 Q_ASSERT(size < INT_MAX);
377 return int(size);
378 }
379
380 static size_t align(size_t a) {
381 return (a + 7) & ~size_t(7);
382 }
383};
384static_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");
385
386struct TemplateObject
387{
388 quint32_le size;
389
390 static int calculateSize(int size) {
391 int trailingData = 2 * size * sizeof(quint32_le);
392 size_t s = align(sizeof(TemplateObject) + trailingData);
393 Q_ASSERT(s < INT_MAX);
394 return int(s);
395 }
396
397 static size_t align(size_t a) {
398 return (a + 7) & ~size_t(7);
399 }
400
401 const quint32_le *stringTable() const {
402 return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
403 }
404
405 uint stringIndexAt(uint i) const {
406 return stringTable()[i];
407 }
408 uint rawStringIndexAt(uint i) const {
409 return stringTable()[size + i];
410 }
411};
412static_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");
413
414struct ExportEntry
415{
416 quint32_le exportName;
417 quint32_le moduleRequest;
418 quint32_le importName;
419 quint32_le localName;
420 Location location;
421};
422static_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");
423
424struct ImportEntry
425{
426 quint32_le moduleRequest;
427 quint32_le importName;
428 quint32_le localName;
429 Location location;
430};
431static_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");
432
433// Qml data structures
434
435struct TranslationData
436{
437 quint32_le stringIndex;
438 quint32_le commentIndex;
439 qint32_le number;
440 quint32_le padding;
441};
442static_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");
443
444struct Binding
445{
446 quint32_le propertyNameIndex;
447
448 enum ValueType : unsigned int {
449 Type_Invalid,
450 Type_Boolean,
451 Type_Number,
452 Type_String,
453 Type_Null,
454 Type_Translation,
455 Type_TranslationById,
456 Type_Script,
457 Type_Object,
458 Type_AttachedProperty,
459 Type_GroupProperty
460 };
461
462 enum Flags : unsigned int {
463 IsSignalHandlerExpression = 0x1,
464 IsSignalHandlerObject = 0x2,
465 IsOnAssignment = 0x4,
466 InitializerForReadOnlyDeclaration = 0x8,
467 IsResolvedEnum = 0x10,
468 IsListItem = 0x20,
469 IsBindingToAlias = 0x40,
470 IsDeferredBinding = 0x80,
471 IsCustomParserBinding = 0x100,
472 IsFunctionExpression = 0x200
473 };
474
475 union {
476 quint32_le_bitfield<0, 16> flags;
477 quint32_le_bitfield<16, 16> type;
478 };
479 union {
480 bool b;
481 quint32_le constantValueIndex;
482 quint32_le compiledScriptIndex; // used when Type_Script
483 quint32_le objectIndex;
484 quint32_le translationDataIndex; // used when Type_Translation
485 quint32 nullMarker;
486 } value;
487 quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
488
489 Location location;
490 Location valueLocation;
491
492 bool isValueBinding() const
493 {
494 if (type == Type_AttachedProperty
495 || type == Type_GroupProperty)
496 return false;
497 if (flags & IsSignalHandlerExpression
498 || flags & IsSignalHandlerObject)
499 return false;
500 return true;
501 }
502
503 bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
504 bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
505
506 bool isSignalHandler() const
507 {
508 if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
509 Q_ASSERT(!isValueBinding());
510 Q_ASSERT(!isAttachedProperty());
511 Q_ASSERT(!isGroupProperty());
512 return true;
513 }
514 return false;
515 }
516
517 bool isAttachedProperty() const
518 {
519 if (type == Type_AttachedProperty) {
520 Q_ASSERT(!isValueBinding());
521 Q_ASSERT(!isSignalHandler());
522 Q_ASSERT(!isGroupProperty());
523 return true;
524 }
525 return false;
526 }
527
528 bool isGroupProperty() const
529 {
530 if (type == Type_GroupProperty) {
531 Q_ASSERT(!isValueBinding());
532 Q_ASSERT(!isSignalHandler());
533 Q_ASSERT(!isAttachedProperty());
534 return true;
535 }
536 return false;
537 }
538
539 bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
540
541 //reverse of Lexer::singleEscape()
542 static QString escapedString(const QString &string)
543 {
544 QString tmp = QLatin1String("\"");
545 for (int i = 0; i < string.length(); ++i) {
546 const QChar &c = string.at(i);
547 switch (c.unicode()) {
548 case 0x08:
549 tmp += QLatin1String("\\b");
550 break;
551 case 0x09:
552 tmp += QLatin1String("\\t");
553 break;
554 case 0x0A:
555 tmp += QLatin1String("\\n");
556 break;
557 case 0x0B:
558 tmp += QLatin1String("\\v");
559 break;
560 case 0x0C:
561 tmp += QLatin1String("\\f");
562 break;
563 case 0x0D:
564 tmp += QLatin1String("\\r");
565 break;
566 case 0x22:
567 tmp += QLatin1String("\\\"");
568 break;
569 case 0x27:
570 tmp += QLatin1String("\\\'");
571 break;
572 case 0x5C:
573 tmp += QLatin1String("\\\\");
574 break;
575 default:
576 tmp += c;
577 break;
578 }
579 }
580 tmp += QLatin1Char('\"');
581 return tmp;
582 }
583
584 bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
585 bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
586
587 bool valueAsBoolean() const
588 {
589 if (type == Type_Boolean)
590 return value.b;
591 return false;
592 }
593
594};
595
596static_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");
597
598struct EnumValue
599{
600 quint32_le nameIndex;
601 qint32_le value;
602 Location location;
603};
604static_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");
605
606struct Enum
607{
608 quint32_le nameIndex;
609 quint32_le nEnumValues;
610 Location location;
611
612 const EnumValue *enumValueAt(int idx) const {
613 return reinterpret_cast<const EnumValue*>(this + 1) + idx;
614 }
615
616 static int calculateSize(int nEnumValues) {
617 return (sizeof(Enum)
618 + nEnumValues * sizeof(EnumValue)
619 + 7) & ~0x7;
620 }
621
622 // --- QQmlPropertyCacheCreatorInterface
623 const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
624 const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
625 int enumValueCount() const { return nEnumValues; }
626 // ---
627};
628static_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");
629
630struct Signal
631{
632 quint32_le nameIndex;
633 quint32_le nParameters;
634 Location location;
635 // Parameter parameters[1];
636
637 const Parameter *parameterAt(int idx) const {
638 return reinterpret_cast<const Parameter*>(this + 1) + idx;
639 }
640
641 static int calculateSize(int nParameters) {
642 return (sizeof(Signal)
643 + nParameters * sizeof(Parameter)
644 + 7) & ~0x7;
645 }
646
647 // --- QQmlPropertyCacheCceatorInterface
648 const Parameter *parametersBegin() const { return parameterAt(0); }
649 const Parameter *parametersEnd() const { return parameterAt(nParameters); }
650 int parameterCount() const { return nParameters; }
651 // ---
652};
653static_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");
654
655struct Property
656{
657 quint32_le nameIndex;
658 union {
659 quint32_le_bitfield<0, 29> builtinTypeOrTypeNameIndex;
660 quint32_le_bitfield<29, 1> isBuiltinType;
661 quint32_le_bitfield<30, 1> isList;
662 quint32_le_bitfield<31, 1> isReadOnly;
663 };
664
665 Location location;
666
667 void setBuiltinType(BuiltinType t)
668 {
669 builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
670 isBuiltinType = true;
671 }
672 BuiltinType builtinType() const {
673 if (isBuiltinType)
674 return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
675 return BuiltinType::InvalidBuiltin;
676 }
677 void setCustomType(int nameIndex)
678 {
679 builtinTypeOrTypeNameIndex = nameIndex;
680 isBuiltinType = false;
681 }
682};
683static_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");
684
685struct Alias {
686 enum Flags : unsigned int {
687 IsReadOnly = 0x1,
688 Resolved = 0x2,
689 AliasPointsToPointerObject = 0x4
690 };
691 union {
692 quint32_le_bitfield<0, 29> nameIndex;
693 quint32_le_bitfield<29, 3> flags;
694 };
695 union {
696 quint32_le idIndex; // string index
697 quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
698 quint32_le_bitfield<31, 1> aliasToLocalAlias;
699 };
700 union {
701 quint32_le propertyNameIndex; // string index
702 qint32_le encodedMetaPropertyIndex;
703 quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
704 };
705 Location location;
706 Location referenceLocation;
707
708 bool isObjectAlias() const {
709 Q_ASSERT(flags & Resolved);
710 return encodedMetaPropertyIndex == -1;
711 }
712};
713static_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");
714
715struct Object
716{
717 enum Flags : unsigned int {
718 NoFlag = 0x0,
719 IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
720 HasDeferredBindings = 0x2, // any of the bindings are deferred
721 HasCustomParserBindings = 0x4
722 };
723
724 // Depending on the use, this may be the type name to instantiate before instantiating this
725 // object. For grouped properties the type name will be empty and for attached properties
726 // it will be the name of the attached type.
727 quint32_le inheritedTypeNameIndex;
728 quint32_le idNameIndex;
729 union {
730 quint32_le_bitfield<0, 15> flags;
731 quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
732 qint32_le_bitfield<16, 16> id;
733 };
734 qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
735 quint16_le nFunctions;
736 quint16_le nProperties;
737 quint32_le offsetToFunctions;
738 quint32_le offsetToProperties;
739 quint32_le offsetToAliases;
740 quint16_le nAliases;
741 quint16_le nEnums;
742 quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
743 quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
744 quint16_le nSignals;
745 quint16_le nBindings;
746 quint32_le offsetToBindings;
747 quint32_le nNamedObjectsInComponent;
748 quint32_le offsetToNamedObjectsInComponent;
749 Location location;
750 Location locationOfIdProperty;
751// Function[]
752// Property[]
753// Signal[]
754// Binding[]
755
756 static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent)
757 {
758 return ( sizeof(Object)
759 + nFunctions * sizeof(quint32)
760 + nProperties * sizeof(Property)
761 + nAliases * sizeof(Alias)
762 + nEnums * sizeof(quint32)
763 + nSignals * sizeof(quint32)
764 + nBindings * sizeof(Binding)
765 + nNamedObjectsInComponent * sizeof(int)
766 + 0x7
767 ) & ~0x7;
768 }
769
770 const quint32_le *functionOffsetTable() const
771 {
772 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
773 }
774
775 const Property *propertyTable() const
776 {
777 return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
778 }
779
780 const Alias *aliasTable() const
781 {
782 return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
783 }
784
785 const Binding *bindingTable() const
786 {
787 return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
788 }
789
790 const Enum *enumAt(int idx) const
791 {
792 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
793 const quint32_le offset = offsetTable[idx];
794 return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
795 }
796
797 const Signal *signalAt(int idx) const
798 {
799 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
800 const quint32_le offset = offsetTable[idx];
801 return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
802 }
803
804 const quint32_le *namedObjectsInComponentTable() const
805 {
806 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
807 }
808
809 // --- QQmlPropertyCacheCreator interface
810 int propertyCount() const { return nProperties; }
811 int aliasCount() const { return nAliases; }
812 int enumCount() const { return nEnums; }
813 int signalCount() const { return nSignals; }
814 int functionCount() const { return nFunctions; }
815
816 const Binding *bindingsBegin() const { return bindingTable(); }
817 const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
818
819 const Property *propertiesBegin() const { return propertyTable(); }
820 const Property *propertiesEnd() const { return propertyTable() + nProperties; }
821
822 const Alias *aliasesBegin() const { return aliasTable(); }
823 const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
824
825 typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator;
826 EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
827 EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
828
829 typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
830 SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
831 SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
832
833 int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
834 // ---
835};
836static_assert(sizeof(Object) == 68, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
837
838struct Import
839{
840 enum ImportType : unsigned int {
841 ImportLibrary = 0x1,
842 ImportFile = 0x2,
843 ImportScript = 0x3
844 };
845 quint32_le type;
846
847 quint32_le uriIndex;
848 quint32_le qualifierIndex;
849
850 qint32_le majorVersion;
851 qint32_le minorVersion;
852
853 Location location;
854
855 Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
856};
857static_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");
858
859struct QmlUnit
860{
861 quint32_le nImports;
862 quint32_le offsetToImports;
863 quint32_le nObjects;
864 quint32_le offsetToObjects;
865
866 const Import *importAt(int idx) const {
867 return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
868 }
869
870 const Object *objectAt(int idx) const {
871 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
872 const quint32_le offset = offsetTable[idx];
873 return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
874 }
875};
876static_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");
877
878enum { QmlCompileHashSpace = 48 };
879static const char magic_str[] = "qv4cdata";
880
881struct Unit
882{
883 // DO NOT CHANGE THESE FIELDS EVER
884 char magic[8];
885 quint32_le version;
886 quint32_le qtVersion;
887 qint64_le sourceTimeStamp;
888 quint32_le unitSize; // Size of the Unit and any depending data.
889 // END DO NOT CHANGE THESE FIELDS EVER
890
891 char libraryVersionHash[QmlCompileHashSpace];
892
893 char md5Checksum[16]; // checksum of all bytes following this field.
894 char dependencyMD5Checksum[16];
895
896 enum : unsigned int {
897 IsJavascript = 0x1,
898 StaticData = 0x2, // Unit data persistent in memory?
899 IsSingleton = 0x4,
900 IsSharedLibrary = 0x8, // .pragma shared?
901 IsESModule = 0x10,
902 PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation
903 };
904 quint32_le flags;
905 quint32_le stringTableSize;
906 quint32_le offsetToStringTable;
907 quint32_le functionTableSize;
908 quint32_le offsetToFunctionTable;
909 quint32_le classTableSize;
910 quint32_le offsetToClassTable;
911 quint32_le templateObjectTableSize;
912 quint32_le offsetToTemplateObjectTable;
913 quint32_le blockTableSize;
914 quint32_le offsetToBlockTable;
915 quint32_le lookupTableSize;
916 quint32_le offsetToLookupTable;
917 quint32_le regexpTableSize;
918 quint32_le offsetToRegexpTable;
919 quint32_le constantTableSize;
920 quint32_le offsetToConstantTable;
921 quint32_le jsClassTableSize;
922 quint32_le offsetToJSClassTable;
923 quint32_le translationTableSize;
924 quint32_le offsetToTranslationTable;
925 quint32_le localExportEntryTableSize;
926 quint32_le offsetToLocalExportEntryTable;
927 quint32_le indirectExportEntryTableSize;
928 quint32_le offsetToIndirectExportEntryTable;
929 quint32_le starExportEntryTableSize;
930 quint32_le offsetToStarExportEntryTable;
931 quint32_le importEntryTableSize;
932 quint32_le offsetToImportEntryTable;
933 quint32_le moduleRequestTableSize;
934 quint32_le offsetToModuleRequestTable;
935 qint32_le indexOfRootFunction;
936 quint32_le sourceFileIndex;
937 quint32_le finalUrlIndex;
938
939 quint32_le offsetToQmlUnit;
940
941 /* QML specific fields */
942
943 const QmlUnit *qmlUnit() const {
944 return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
945 }
946
947 QmlUnit *qmlUnit() {
948 return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
949 }
950
951 bool isSingleton() const {
952 return flags & Unit::IsSingleton;
953 }
954 /* end QML specific fields*/
955
956 QString stringAtInternal(int idx) const {
957 Q_ASSERT(idx < int(stringTableSize));
958 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
959 const quint32_le offset = offsetTable[idx];
960 const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
961 if (str->size == 0)
962 return QString();
963#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
964 if (flags & StaticData) {
965 const QStringDataPtr holder = { const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) };
966 return QString(holder);
967 }
968 const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
969 return QString(characters, str->size);
970#else
971 const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
972 QString qstr(str->size, Qt::Uninitialized);
973 QChar *ch = qstr.data();
974 for (int i = 0; i < str->size; ++i)
975 ch[i] = QChar(characters[i]);
976 return qstr;
977#endif
978 }
979
980 const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
981 const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
982 const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
983 const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
984
985 const Function *functionAt(int idx) const {
986 const quint32_le *offsetTable = functionOffsetTable();
987 const quint32_le offset = offsetTable[idx];
988 return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
989 }
990
991 const Class *classAt(int idx) const {
992 const quint32_le *offsetTable = classOffsetTable();
993 const quint32_le offset = offsetTable[idx];
994 return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
995 }
996
997 const TemplateObject *templateObjectAt(int idx) const {
998 const quint32_le *offsetTable = templateObjectOffsetTable();
999 const quint32_le offset = offsetTable[idx];
1000 return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
1001 }
1002
1003 const Block *blockAt(int idx) const {
1004 const quint32_le *offsetTable = blockOffsetTable();
1005 const quint32_le offset = offsetTable[idx];
1006 return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
1007 }
1008
1009 const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
1010 const RegExp *regexpAt(int index) const {
1011 return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
1012 }
1013 const quint64_le *constants() const {
1014 return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
1015 }
1016
1017 const JSClassMember *jsClassAt(int idx, int *nMembers) const {
1018 const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
1019 const quint32_le offset = offsetTable[idx];
1020 const char *ptr = reinterpret_cast<const char *>(this) + offset;
1021 const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
1022 *nMembers = klass->nMembers;
1023 return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
1024 }
1025
1026 const TranslationData *translations() const {
1027 return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
1028 }
1029
1030 const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
1031 const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
1032 const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
1033 const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
1034
1035 const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
1036};
1037
1038static_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");
1039
1040struct TypeReference
1041{
1042 TypeReference(const Location &loc)
1043 : location(loc)
1044 , needsCreation(false)
1045 , errorWhenNotFound(false)
1046 {}
1047 Location location; // first use
1048 bool needsCreation : 1; // whether the type needs to be creatable or not
1049 bool errorWhenNotFound: 1;
1050};
1051
1052// Map from name index to location of first use.
1053struct TypeReferenceMap : QHash<int, TypeReference>
1054{
1055 TypeReference &add(int nameIndex, const Location &loc) {
1056 Iterator it = find(nameIndex);
1057 if (it != end())
1058 return *it;
1059 return *insert(nameIndex, loc);
1060 }
1061
1062 template <typename CompiledObject>
1063 void collectFromObject(const CompiledObject *obj)
1064 {
1065 if (obj->inheritedTypeNameIndex != 0) {
1066 TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
1067 r.needsCreation = true;
1068 r.errorWhenNotFound = true;
1069 }
1070
1071 auto prop = obj->propertiesBegin();
1072 auto propEnd = obj->propertiesEnd();
1073 for ( ; prop != propEnd; ++prop) {
1074 if (!prop->isBuiltinType) {
1075 TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
1076 r.errorWhenNotFound = true;
1077 }
1078 }
1079
1080 auto binding = obj->bindingsBegin();
1081 auto bindingEnd = obj->bindingsEnd();
1082 for ( ; binding != bindingEnd; ++binding) {
1083 if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
1084 this->add(binding->propertyNameIndex, binding->location);
1085 }
1086 }
1087
1088 template <typename Iterator>
1089 void collectFromObjects(Iterator it, Iterator end)
1090 {
1091 for (; it != end; ++it)
1092 collectFromObject(*it);
1093 }
1094};
1095
1096using DependentTypesHasher = std::function<QByteArray()>;
1097
1098// This is how this hooks into the existing structures:
1099
1100struct CompilationUnitBase
1101{
1102 Q_DISABLE_COPY(CompilationUnitBase)
1103
1104 CompilationUnitBase() = default;
1105 ~CompilationUnitBase() = default;
1106
1107 CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); }
1108
1109 CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept
1110 {
1111 if (this != &other) {
1112 runtimeStrings = other.runtimeStrings;
1113 other.runtimeStrings = nullptr;
1114 constants = other.constants;
1115 other.constants = nullptr;
1116 runtimeRegularExpressions = other.runtimeRegularExpressions;
1117 other.runtimeRegularExpressions = nullptr;
1118 runtimeClasses = other.runtimeClasses;
1119 other.runtimeClasses = nullptr;
1120 imports = other.imports;
1121 other.imports = nullptr;
1122 }
1123 return *this;
1124 }
1125
1126 // pointers either to data->constants() or little-endian memory copy.
1127 Heap::String **runtimeStrings = nullptr; // Array
1128 const StaticValue* constants = nullptr;
1129 QV4::StaticValue *runtimeRegularExpressions = nullptr;
1130 Heap::InternalClass **runtimeClasses = nullptr;
1131 const StaticValue** imports = nullptr;
1132};
1133
1134Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
1135Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
1136Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
1137Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
1138Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
1139Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
1140
1141struct CompilationUnit : public CompilationUnitBase
1142{
1143 Q_DISABLE_COPY(CompilationUnit)
1144
1145 const Unit *data = nullptr;
1146 const QmlUnit *qmlData = nullptr;
1147 QStringList dynamicStrings;
1148public:
1149 using CompiledObject = CompiledData::Object;
1150
1151 CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(),
1152 const QString &finalUrlString = QString())
1153 {
1154 setUnitData(unitData, nullptr, fileName, finalUrlString);
1155 }
1156
1157 ~CompilationUnit()
1158 {
1159 if (data) {
1160 if (data->qmlUnit() != qmlData)
1161 free(const_cast<QmlUnit *>(qmlData));
1162 qmlData = nullptr;
1163
1164 if (!(data->flags & QV4::CompiledData::Unit::StaticData))
1165 free(const_cast<Unit *>(data));
1166 }
1167 data = nullptr;
1168#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1169 delete [] constants;
1170 constants = nullptr;
1171#endif
1172
1173 delete [] imports;
1174 imports = nullptr;
1175 }
1176
1177 CompilationUnit(CompilationUnit &&other) noexcept
1178 {
1179 *this = std::move(other);
1180 }
1181
1182 CompilationUnit &operator=(CompilationUnit &&other) noexcept
1183 {
1184 if (this != &other) {
1185 data = other.data;
1186 other.data = nullptr;
1187 qmlData = other.qmlData;
1188 other.qmlData = nullptr;
1189 dynamicStrings = std::move(other.dynamicStrings);
1190 other.dynamicStrings.clear();
1191 m_fileName = std::move(other.m_fileName);
1192 other.m_fileName.clear();
1193 m_finalUrlString = std::move(other.m_finalUrlString);
1194 other.m_finalUrlString.clear();
1195 m_module = other.m_module;
1196 other.m_module = nullptr;
1197 CompilationUnitBase::operator=(std::move(other));
1198 }
1199 return *this;
1200 }
1201
1202 const Unit *unitData() const { return data; }
1203
1204 void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
1205 const QString &fileName = QString(), const QString &finalUrlString = QString())
1206 {
1207 data = unitData;
1208 qmlData = nullptr;
1209#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1210 delete [] constants;
1211#endif
1212 constants = nullptr;
1213 m_fileName.clear();
1214 m_finalUrlString.clear();
1215 if (!data)
1216 return;
1217
1218 qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
1219
1220#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1221 StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
1222 const quint64_le *littleEndianConstants = data->constants();
1223 for (uint i = 0; i < data->constantTableSize; ++i)
1224 bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
1225 constants = bigEndianConstants;
1226#else
1227 constants = reinterpret_cast<const StaticValue*>(data->constants());
1228#endif
1229
1230 m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
1231 m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
1232 }
1233
1234 QString stringAt(int index) const
1235 {
1236 if (uint(index) >= data->stringTableSize)
1237 return dynamicStrings.at(index - data->stringTableSize);
1238 return data->stringAtInternal(index);
1239 }
1240
1241 QString fileName() const { return m_fileName; }
1242 QString finalUrlString() const { return m_finalUrlString; }
1243
1244 Heap::Module *module() const { return m_module; }
1245 void setModule(Heap::Module *module) { m_module = module; }
1246
1247private:
1248 QString m_fileName; // initialized from data->sourceFileIndex
1249 QString m_finalUrlString; // initialized from data->finalUrlIndex
1250
1251 Heap::Module *m_module = nullptr;
1252};
1253
1254class SaveableUnitPointer
1255{
1256 Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
1257public:
1258 SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) :
1259 unit(unit),
1260 temporaryFlags(temporaryFlags)
1261 {
1262 }
1263
1264 ~SaveableUnitPointer() = default;
1265
1266 template<typename Char>
1267 bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
1268 {
1269 auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; });
1270 mutableFlags() |= temporaryFlags;
1271 return writer(data<Char>(), size());
1272 }
1273
1274 static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
1275 QString *errorString)
1276 {
1277#if QT_CONFIG(temporaryfile)
1278 QSaveFile cacheFile(outputFileName);
1279 if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
1280 || cacheFile.write(data, size) != size
1281 || !cacheFile.commit()) {
1282 *errorString = cacheFile.errorString();
1283 return false;
1284 }
1285
1286 errorString->clear();
1287 return true;
1288#else
1289 Q_UNUSED(outputFileName)
1290 *errorString = QStringLiteral("features.temporaryfile is disabled.");
1291 return false;
1292#endif
1293 }
1294
1295private:
1296 const Unit *unit;
1297 quint32 temporaryFlags;
1298
1299 quint32_le &mutableFlags() const
1300 {
1301 return const_cast<Unit *>(unit)->flags;
1302 }
1303
1304 template<typename Char>
1305 const Char *data() const
1306 {
1307 Q_STATIC_ASSERT(sizeof(Char) == 1);
1308 const Char *dataPtr;
1309 memcpy(&dataPtr, &unit, sizeof(dataPtr));
1310 return dataPtr;
1311 }
1312
1313 quint32 size() const
1314 {
1315 return unit->unitSize;
1316 }
1317};
1318
1319
1320} // CompiledData namespace
1321} // QV4 namespace
1322
1323Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
1324
1325QT_END_NAMESPACE
1326
1327#endif
1328