1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QV4COMPILEDDATA_P_H
4#define QV4COMPILEDDATA_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <functional>
18
19#include <QtCore/qhashfunctions.h>
20#include <QtCore/qstring.h>
21#include <QtCore/qscopeguard.h>
22#include <QtCore/qvector.h>
23#include <QtCore/qstringlist.h>
24#include <QtCore/qhash.h>
25#include <QtCore/qversionnumber.h>
26#include <QtCore/qlocale.h>
27
28#if QT_CONFIG(temporaryfile)
29#include <QtCore/qsavefile.h>
30#endif
31
32#include <private/qendian_p.h>
33#include <private/qv4staticvalue_p.h>
34#include <functional>
35#include <limits.h>
36
37QT_BEGIN_NAMESPACE
38
39// Bump this whenever the compiler data structures change in an incompatible way.
40//
41// IMPORTANT:
42//
43// Also change the comment behind the number to describe the latest change. This has the added
44// benefit that if another patch changes the version too, it will result in a merge conflict, and
45// not get removed silently.
46#define QV4_DATA_STRUCTURE_VERSION 0x3C // Restructured builtin type enums
47
48class QIODevice;
49class QQmlTypeNameCache;
50class QQmlType;
51class QQmlEngine;
52
53namespace QQmlPrivate {
54struct AOTCompiledFunction;
55}
56
57namespace QmlIR {
58struct Document;
59}
60
61namespace QV4 {
62namespace Heap {
63struct Module;
64struct String;
65struct InternalClass;
66};
67
68struct Function;
69class EvalISelFactory;
70
71namespace CompiledData {
72
73struct String;
74struct Function;
75struct Lookup;
76struct RegExp;
77struct Unit;
78
79template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
80struct TableIterator
81{
82 TableIterator(const Container *container, int index) : container(container), index(index) {}
83 const Container *container;
84 int index;
85
86 const ItemType *operator->() { return (container->*IndexedGetter)(index); }
87 ItemType operator*() {return *operator->();}
88 void operator++() { ++index; }
89 bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
90 bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
91};
92
93struct Location
94{
95 Location() : m_data(QSpecialIntegerBitfieldZero) {}
96 Location(quint32 l, quint32 c) : Location()
97 {
98 m_data.set<LineField>(l);
99 m_data.set<ColumnField>(c);
100 Q_ASSERT(m_data.get<LineField>() == l);
101 Q_ASSERT(m_data.get<ColumnField>() == c);
102 }
103
104 inline bool operator<(const Location &other) const {
105 return m_data.get<LineField>() < other.m_data.get<LineField>()
106 || (m_data.get<LineField>() == other.m_data.get<LineField>()
107 && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
108 }
109
110 friend size_t qHash(const Location &location, size_t seed = 0)
111 {
112 return QT_PREPEND_NAMESPACE(qHash)(key: location.m_data.data(), seed);
113 }
114
115 friend bool operator==(const Location &a, const Location &b)
116 {
117 return a.m_data.data()== b.m_data.data();
118 }
119
120 void set(quint32 line, quint32 column)
121 {
122 m_data.set<LineField>(line);
123 m_data.set<ColumnField>(column);
124 }
125
126 quint32 line() const { return m_data.get<LineField>(); }
127 quint32 column() const { return m_data.get<ColumnField>(); }
128
129private:
130 using LineField = quint32_le_bitfield_member<0, 20>;
131 using ColumnField = quint32_le_bitfield_member<20, 12>;
132
133 quint32_le_bitfield_union<LineField, ColumnField> m_data;
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
148 RegExp() : m_data(QSpecialIntegerBitfieldZero) {}
149 RegExp(quint32 flags, quint32 stringIndex) : RegExp()
150 {
151 m_data.set<FlagsField>(flags);
152 m_data.set<StringIndexField>(stringIndex);
153 }
154
155 quint32 flags() const { return m_data.get<FlagsField>(); }
156 quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
157
158private:
159 using FlagsField = quint32_le_bitfield_member<0, 5>;
160 using StringIndexField = quint32_le_bitfield_member<5, 27>;
161 quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
162};
163static_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");
164
165struct Lookup
166{
167 enum Type : unsigned int {
168 Type_Getter = 0,
169 Type_Setter = 1,
170 Type_GlobalGetter = 2,
171 Type_QmlContextPropertyGetter = 3
172 };
173
174 enum Mode : unsigned int {
175 Mode_ForStorage = 0,
176 Mode_ForCall = 1
177 };
178
179 quint32 type() const { return m_data.get<TypeField>(); }
180 quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
181 quint32 mode() const { return m_data.get<ModeField>(); }
182
183 Lookup() : m_data(QSpecialIntegerBitfieldZero) {}
184 Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup()
185 {
186 m_data.set<TypeField>(type);
187 m_data.set<ModeField>(mode);
188 m_data.set<NameIndexField>(nameIndex);
189 }
190
191private:
192 using TypeField = quint32_le_bitfield_member<0, 2>;
193 using ModeField = quint32_le_bitfield_member<2, 1>;
194 // 1 bit left
195 using NameIndexField = quint32_le_bitfield_member<4, 28>;
196 quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data;
197};
198static_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");
199
200struct JSClassMember
201{
202 JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {}
203
204 void set(quint32 nameOffset, bool isAccessor)
205 {
206 m_data.set<NameOffsetField>(nameOffset);
207 m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
208 }
209
210 quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
211 bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
212
213private:
214 using NameOffsetField = quint32_le_bitfield_member<0, 31>;
215 using IsAccessorField = quint32_le_bitfield_member<31, 1>;
216 quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
217};
218static_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");
219
220struct JSClass
221{
222 quint32_le nMembers;
223 // JSClassMember[nMembers]
224
225 static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
226};
227static_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");
228
229struct String
230{
231 qint32_le size;
232
233 static int calculateSize(const QString &str) {
234 // we cannot enconuter strings larger than INT_MAX anyway, as such a string
235 // would already break in other parts of the compilation process
236 return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7;
237 }
238};
239
240static_assert (sizeof (String) == 4, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
241
242struct CodeOffsetToLineAndStatement {
243 quint32_le codeOffset;
244 qint32_le line; // signed because debug instructions get negative line numbers
245 quint32_le statement;
246};
247static_assert(sizeof(CodeOffsetToLineAndStatement) == 12, "CodeOffsetToLineAndStatement structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
248
249struct Block
250{
251 quint32_le nLocals;
252 quint32_le localsOffset;
253 quint16_le sizeOfLocalTemporalDeadZone;
254 quint16_le padding;
255
256 const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
257
258 static int calculateSize(int nLocals) {
259 int trailingData = nLocals*sizeof (quint32);
260 size_t size = align(a: align(a: sizeof(Block)) + size_t(trailingData));
261 Q_ASSERT(size < INT_MAX);
262 return int(size);
263 }
264
265 static size_t align(size_t a) {
266 return (a + 7) & ~size_t(7);
267 }
268};
269static_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");
270
271enum class NamedBuiltin: unsigned int {
272 Void, Var, Int, Bool, Real, String, Url, DateTime, RegExp
273};
274
275enum class CommonType : unsigned int {
276 // Actual named builtins
277 Void = uint(NamedBuiltin::Void),
278 Var = uint(NamedBuiltin::Var),
279 Int = uint(NamedBuiltin::Int),
280 Bool = uint(NamedBuiltin::Bool),
281 Real = uint(NamedBuiltin::Real),
282 String = uint(NamedBuiltin::String),
283 Url = uint(NamedBuiltin::Url),
284 DateTime = uint(NamedBuiltin::DateTime),
285 RegExp = uint(NamedBuiltin::RegExp),
286
287 // Optimization for very common other types
288 Time, Date, Rect, Point, Size,
289
290 // No type specified or not recognized
291 Invalid
292};
293
294struct ParameterType
295{
296 enum Flag {
297 NoFlag = 0x0,
298 Common = 0x1,
299 List = 0x2,
300 };
301 Q_DECLARE_FLAGS(Flags, Flag);
302
303 void set(Flags flags, quint32 typeNameIndexOrCommonType)
304 {
305 m_data.set<IsListField>(flags.testFlag(flag: List) ? 1 : 0);
306 m_data.set<IndexIsCommonTypeField>(flags.testFlag(flag: Common) ? 1 : 0);
307 m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType);
308 }
309
310 bool indexIsCommonType() const
311 {
312 return m_data.get<IndexIsCommonTypeField>() != 0;
313 }
314
315 bool isList() const
316 {
317 return m_data.get<IsListField>() != 0;
318 }
319
320 quint32 typeNameIndexOrCommonType() const
321 {
322 return m_data.get<TypeNameIndexOrCommonTypeField>();
323 }
324
325private:
326 using IndexIsCommonTypeField = quint32_le_bitfield_member<0, 1>;
327 using IsListField = quint32_le_bitfield_member<1, 1>;
328 using TypeNameIndexOrCommonTypeField = quint32_le_bitfield_member<2, 30>;
329 quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data;
330};
331static_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");
332
333struct Parameter
334{
335 quint32_le nameIndex;
336 ParameterType type;
337};
338static_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");
339
340// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
341// for unaligned access. The ordering of the fields is also from largest to smallest.
342struct Function
343{
344 enum Flags : unsigned int {
345 IsStrict = 0x1,
346 IsArrowFunction = 0x2,
347 IsGenerator = 0x4,
348 IsClosureWrapper = 0x8,
349 };
350
351 // Absolute offset into file where the code for this function is located.
352 quint32_le codeOffset;
353 quint32_le codeSize;
354
355 quint32_le nameIndex;
356 quint16_le length;
357 quint16_le nFormals;
358 quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
359 ParameterType returnType;
360 quint32_le localsOffset;
361 quint16_le nLocals;
362 quint16_le nLineAndStatementNumbers;
363 size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
364 quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
365
366 quint32_le nRegisters;
367 Location location;
368 quint32_le nLabelInfos;
369
370 quint16_le sizeOfLocalTemporalDeadZone;
371 quint16_le firstTemporalDeadZoneRegister;
372 quint16_le sizeOfRegisterTemporalDeadZone;
373
374 size_t labelInfosOffset() const
375 {
376 return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement);
377 }
378
379 // Keep all unaligned data at the end
380 quint8 flags;
381 quint8 padding1;
382
383 // quint32 formalsIndex[nFormals]
384 // quint32 localsIndex[nLocals]
385
386 const Parameter *formalsTable() const
387 {
388 return reinterpret_cast<const Parameter *>(
389 reinterpret_cast<const char *>(this) + formalsOffset);
390 }
391 const quint32_le *localsTable() const
392 {
393 return reinterpret_cast<const quint32_le *>(
394 reinterpret_cast<const char *>(this) + localsOffset);
395 }
396 const CodeOffsetToLineAndStatement *lineAndStatementNumberTable() const
397 {
398 return reinterpret_cast<const CodeOffsetToLineAndStatement *>(
399 reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset());
400 }
401
402 // --- QQmlPropertyCacheCreator interface
403 const Parameter *formalsBegin() const { return formalsTable(); }
404 const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
405 // ---
406
407 const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
408
409 const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
410
411 static int calculateSize(
412 int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions,
413 int labelInfoSize, int codeSize)
414 {
415 int trailingData = nFormals * sizeof(Parameter)
416 + (nLocals + nInnerfunctions + labelInfoSize) * sizeof (quint32)
417 + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement);
418 size_t size = align(a: align(a: sizeof(Function)) + size_t(trailingData)) + align(a: codeSize);
419 Q_ASSERT(size < INT_MAX);
420 return int(size);
421 }
422
423 static size_t align(size_t a) {
424 return (a + 7) & ~size_t(7);
425 }
426};
427static_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");
428
429struct Method {
430 enum Type {
431 Regular,
432 Getter,
433 Setter
434 };
435
436 quint32_le name;
437 quint32_le type;
438 quint32_le function;
439};
440static_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");
441
442struct Class
443{
444 quint32_le nameIndex;
445 quint32_le scopeIndex;
446 quint32_le constructorFunction;
447 quint32_le nStaticMethods;
448 quint32_le nMethods;
449 quint32_le methodTableOffset;
450
451 const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
452
453 static int calculateSize(int nStaticMethods, int nMethods) {
454 int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
455 size_t size = align(a: sizeof(Class) + trailingData);
456 Q_ASSERT(size < INT_MAX);
457 return int(size);
458 }
459
460 static size_t align(size_t a) {
461 return (a + 7) & ~size_t(7);
462 }
463};
464static_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");
465
466struct TemplateObject
467{
468 quint32_le size;
469
470 static int calculateSize(int size) {
471 int trailingData = 2 * size * sizeof(quint32_le);
472 size_t s = align(a: sizeof(TemplateObject) + trailingData);
473 Q_ASSERT(s < INT_MAX);
474 return int(s);
475 }
476
477 static size_t align(size_t a) {
478 return (a + 7) & ~size_t(7);
479 }
480
481 const quint32_le *stringTable() const {
482 return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
483 }
484
485 uint stringIndexAt(uint i) const {
486 return stringTable()[i];
487 }
488 uint rawStringIndexAt(uint i) const {
489 return stringTable()[size + i];
490 }
491};
492static_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");
493
494struct ExportEntry
495{
496 quint32_le exportName;
497 quint32_le moduleRequest;
498 quint32_le importName;
499 quint32_le localName;
500 Location location;
501};
502static_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");
503
504struct ImportEntry
505{
506 quint32_le moduleRequest;
507 quint32_le importName;
508 quint32_le localName;
509 Location location;
510};
511static_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");
512
513// Qml data structures
514
515struct TranslationData
516{
517 quint32_le stringIndex;
518 quint32_le commentIndex;
519 qint32_le number;
520 quint32_le contextIndex;
521};
522static_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");
523
524struct Binding
525{
526 quint32_le propertyNameIndex;
527
528 enum Type : unsigned int {
529 Type_Invalid,
530 Type_Boolean,
531 Type_Number,
532 Type_String,
533 Type_Null,
534 Type_Translation,
535 Type_TranslationById,
536 Type_Script,
537 Type_Object,
538 Type_AttachedProperty,
539 Type_GroupProperty
540 };
541
542 enum Flag : unsigned int {
543 IsSignalHandlerExpression = 0x1,
544 IsSignalHandlerObject = 0x2,
545 IsOnAssignment = 0x4,
546 InitializerForReadOnlyDeclaration = 0x8,
547 IsResolvedEnum = 0x10,
548 IsListItem = 0x20,
549 IsBindingToAlias = 0x40,
550 IsDeferredBinding = 0x80,
551 IsCustomParserBinding = 0x100,
552 IsFunctionExpression = 0x200,
553 IsPropertyObserver = 0x400
554 };
555 Q_DECLARE_FLAGS(Flags, Flag);
556
557 using FlagsField = quint32_le_bitfield_member<0, 16>;
558 using TypeField = quint32_le_bitfield_member<16, 16>;
559 quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType;
560
561 void clearFlags() { flagsAndType.set<FlagsField>(0); }
562 void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
563 bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
564 Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
565
566 void setType(Type type) { flagsAndType.set<TypeField>(type); }
567 Type type() const { return Type(flagsAndType.get<TypeField>()); }
568
569 union {
570 bool b;
571 quint32_le constantValueIndex;
572 quint32_le compiledScriptIndex; // used when Type_Script
573 quint32_le objectIndex;
574 quint32_le translationDataIndex; // used when Type_Translation
575 quint32 nullMarker;
576 } value;
577 quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
578
579 Location location;
580 Location valueLocation;
581
582 bool hasSignalHandlerBindingFlag() const
583 {
584 const Flags bindingFlags = flags();
585 return bindingFlags & IsSignalHandlerExpression
586 || bindingFlags & IsSignalHandlerObject
587 || bindingFlags & IsPropertyObserver;
588 }
589
590 bool isValueBinding() const
591 {
592 switch (type()) {
593 case Type_AttachedProperty:
594 case Type_GroupProperty:
595 return false;
596 default:
597 return !hasSignalHandlerBindingFlag();
598 }
599 }
600
601 bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(flag: IsBindingToAlias); }
602 bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(flag: IsBindingToAlias); }
603
604 bool isSignalHandler() const
605 {
606 if (hasSignalHandlerBindingFlag()) {
607 Q_ASSERT(!isValueBinding());
608 Q_ASSERT(!isAttachedProperty());
609 Q_ASSERT(!isGroupProperty());
610 return true;
611 }
612 return false;
613 }
614
615 bool isAttachedProperty() const
616 {
617 if (type() == Type_AttachedProperty) {
618 Q_ASSERT(!isValueBinding());
619 Q_ASSERT(!isSignalHandler());
620 Q_ASSERT(!isGroupProperty());
621 return true;
622 }
623 return false;
624 }
625
626 bool isGroupProperty() const
627 {
628 if (type() == Type_GroupProperty) {
629 Q_ASSERT(!isValueBinding());
630 Q_ASSERT(!isSignalHandler());
631 Q_ASSERT(!isAttachedProperty());
632 return true;
633 }
634 return false;
635 }
636
637 bool isFunctionExpression() const { return hasFlag(flag: IsFunctionExpression); }
638
639 //reverse of Lexer::singleEscape()
640 static QString escapedString(const QString &string)
641 {
642 QString tmp = QLatin1String("\"");
643 for (int i = 0; i < string.size(); ++i) {
644 const QChar &c = string.at(i);
645 switch (c.unicode()) {
646 case 0x08:
647 tmp += QLatin1String("\\b");
648 break;
649 case 0x09:
650 tmp += QLatin1String("\\t");
651 break;
652 case 0x0A:
653 tmp += QLatin1String("\\n");
654 break;
655 case 0x0B:
656 tmp += QLatin1String("\\v");
657 break;
658 case 0x0C:
659 tmp += QLatin1String("\\f");
660 break;
661 case 0x0D:
662 tmp += QLatin1String("\\r");
663 break;
664 case 0x22:
665 tmp += QLatin1String("\\\"");
666 break;
667 case 0x27:
668 tmp += QLatin1String("\\\'");
669 break;
670 case 0x5C:
671 tmp += QLatin1String("\\\\");
672 break;
673 default:
674 tmp += c;
675 break;
676 }
677 }
678 tmp += QLatin1Char('\"');
679 return tmp;
680 }
681
682 bool isTranslationBinding() const
683 {
684 const Binding::Type bindingType = type();
685 return bindingType == Type_Translation || bindingType == Type_TranslationById;
686 }
687 bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); }
688
689 bool valueAsBoolean() const
690 {
691 if (type() == Type_Boolean)
692 return value.b;
693 return false;
694 }
695};
696
697static_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");
698
699struct InlineComponent
700{
701 quint32_le objectIndex;
702 quint32_le nameIndex;
703 Location location;
704};
705
706static_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");
707
708struct EnumValue
709{
710 quint32_le nameIndex;
711 qint32_le value;
712 Location location;
713};
714static_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");
715
716struct Enum
717{
718 quint32_le nameIndex;
719 quint32_le nEnumValues;
720 Location location;
721
722 const EnumValue *enumValueAt(int idx) const {
723 return reinterpret_cast<const EnumValue*>(this + 1) + idx;
724 }
725
726 static int calculateSize(int nEnumValues) {
727 return (sizeof(Enum)
728 + nEnumValues * sizeof(EnumValue)
729 + 7) & ~0x7;
730 }
731
732 // --- QQmlPropertyCacheCreatorInterface
733 const EnumValue *enumValuesBegin() const { return enumValueAt(idx: 0); }
734 const EnumValue *enumValuesEnd() const { return enumValueAt(idx: nEnumValues); }
735 int enumValueCount() const { return nEnumValues; }
736 // ---
737};
738static_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");
739
740struct Signal
741{
742 quint32_le nameIndex;
743 quint32_le nParameters;
744 Location location;
745 // Parameter parameters[1];
746
747 const Parameter *parameterAt(int idx) const {
748 return reinterpret_cast<const Parameter*>(this + 1) + idx;
749 }
750
751 static int calculateSize(int nParameters) {
752 return (sizeof(Signal)
753 + nParameters * sizeof(Parameter)
754 + 7) & ~0x7;
755 }
756
757 // --- QQmlPropertyCacheCceatorInterface
758 const Parameter *parametersBegin() const { return parameterAt(idx: 0); }
759 const Parameter *parametersEnd() const { return parameterAt(idx: nParameters); }
760 int parameterCount() const { return nParameters; }
761 // ---
762};
763static_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");
764
765struct Property
766{
767private:
768 using CommonTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>;
769 using IsRequiredField = quint32_le_bitfield_member<28, 1>;
770 using IsCommonTypeField = quint32_le_bitfield_member<29, 1>;
771 using IsListField = quint32_le_bitfield_member<30, 1>;
772 using IsReadOnlyField = quint32_le_bitfield_member<31, 1>;
773
774public:
775 quint32_le nameIndex;
776 quint32_le_bitfield_union<
777 CommonTypeOrTypeNameIndexField,
778 IsRequiredField,
779 IsCommonTypeField,
780 IsListField,
781 IsReadOnlyField> data;
782 Location location;
783
784 void setCommonType(CommonType t)
785 {
786 data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t));
787 data.set<IsCommonTypeField>(true);
788 }
789
790 CommonType commonType() const {
791 if (data.get<IsCommonTypeField>() != 0)
792 return CommonType(data.get<CommonTypeOrTypeNameIndexField>());
793 return CommonType::Invalid;
794 }
795
796 void setTypeNameIndex(int nameIndex)
797 {
798 data.set<CommonTypeOrTypeNameIndexField>(nameIndex);
799 data.set<IsCommonTypeField>(false);
800 }
801
802 int typeNameIndex() const
803 {
804 return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>();
805 }
806
807 bool isCommonType() const { return data.get<IsCommonTypeField>(); }
808 uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); }
809
810 bool isList() const { return data.get<IsListField>(); }
811 void setIsList(bool isList) { data.set<IsListField>(isList); }
812
813 bool isRequired() const { return data.get<IsRequiredField>(); }
814 void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
815
816 bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
817 void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
818};
819static_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");
820
821struct RequiredPropertyExtraData {
822 quint32_le nameIndex;
823};
824
825static_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");
826
827struct Alias {
828private:
829 using NameIndexField = quint32_le_bitfield_member<0, 29>;
830 using FlagsField = quint32_le_bitfield_member<29, 3>;
831
832 // object id index (in QQmlContextData::idValues)
833 using TargetObjectIdField = quint32_le_bitfield_member<0, 31>;
834 using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>;
835 using IdIndexField = quint32_le_bitfield_member<0, 32>;
836
837public:
838
839 enum Flag : unsigned int {
840 IsReadOnly = 0x1,
841 Resolved = 0x2,
842 AliasPointsToPointerObject = 0x4
843 };
844 Q_DECLARE_FLAGS(Flags, Flag)
845
846 quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags;
847 quint32_le_bitfield_union<IdIndexField, TargetObjectIdField, AliasToLocalAliasField>
848 idIndexAndTargetObjectIdAndAliasToLocalAlias;
849
850 union {
851 quint32_le propertyNameIndex; // string index
852 qint32_le encodedMetaPropertyIndex;
853 quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
854 };
855 Location location;
856 Location referenceLocation;
857
858 bool hasFlag(Flag flag) const
859 {
860 return nameIndexAndFlags.get<FlagsField>() & flag;
861 }
862
863 void setFlag(Flag flag)
864 {
865 nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag);
866 }
867
868 void clearFlags()
869 {
870 nameIndexAndFlags.set<FlagsField>(0);
871 }
872
873 quint32 nameIndex() const
874 {
875 return nameIndexAndFlags.get<NameIndexField>();
876 }
877
878 void setNameIndex(quint32 nameIndex)
879 {
880 nameIndexAndFlags.set<NameIndexField>(nameIndex);
881 }
882
883 bool isObjectAlias() const
884 {
885 Q_ASSERT(hasFlag(Resolved));
886 return encodedMetaPropertyIndex == -1;
887 }
888
889 quint32 idIndex() const
890 {
891 return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<IdIndexField>();
892 }
893
894 void setIdIndex(quint32 idIndex)
895 {
896 idIndexAndTargetObjectIdAndAliasToLocalAlias.set<IdIndexField>(idIndex);
897 }
898
899
900 bool isAliasToLocalAlias() const
901 {
902 return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>();
903 }
904
905 void setIsAliasToLocalAlias(bool isAliasToLocalAlias)
906 {
907 idIndexAndTargetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias);
908 }
909
910 quint32 targetObjectId() const
911 {
912 return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>();
913 }
914
915 void setTargetObjectId(quint32 targetObjectId)
916 {
917 idIndexAndTargetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId);
918 }
919};
920static_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");
921
922struct Object
923{
924private:
925 using FlagsField = quint32_le_bitfield_member<0, 15>;
926 using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>;
927 using IdField = quint32_le_bitfield_member<16, 16, qint32>;
928public:
929 enum Flag : unsigned int {
930 NoFlag = 0x0,
931 IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
932 HasDeferredBindings = 0x2, // any of the bindings are deferred
933 HasCustomParserBindings = 0x4,
934 IsInlineComponentRoot = 0x8,
935 IsPartOfInlineComponent = 0x10
936 };
937 Q_DECLARE_FLAGS(Flags, Flag);
938
939 // Depending on the use, this may be the type name to instantiate before instantiating this
940 // object. For grouped properties the type name will be empty and for attached properties
941 // it will be the name of the attached type.
942 quint32_le inheritedTypeNameIndex;
943 quint32_le idNameIndex;
944 quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField>
945 flagsAndDefaultPropertyIsAliasAndId;
946 qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
947 quint16_le nFunctions;
948 quint16_le nProperties;
949 quint32_le offsetToFunctions;
950 quint32_le offsetToProperties;
951 quint32_le offsetToAliases;
952 quint16_le nAliases;
953 quint16_le nEnums;
954 quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
955 quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
956 quint16_le nSignals;
957 quint16_le nBindings;
958 quint32_le offsetToBindings;
959 quint32_le nNamedObjectsInComponent;
960 quint32_le offsetToNamedObjectsInComponent;
961 Location location;
962 Location locationOfIdProperty;
963 quint32_le offsetToInlineComponents;
964 quint16_le nInlineComponents;
965 quint32_le offsetToRequiredPropertyExtraData;
966 quint16_le nRequiredPropertyExtraData;
967// Function[]
968// Property[]
969// Signal[]
970// Binding[]
971// InlineComponent[]
972// RequiredPropertyExtraData[]
973
974 Flags flags() const
975 {
976 return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>());
977 }
978
979 bool hasFlag(Flag flag) const
980 {
981 return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag;
982 }
983
984 void setFlag(Flag flag)
985 {
986 flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(
987 flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag);
988 }
989
990 void setFlags(Flags flags)
991 {
992 flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags);
993 }
994
995 bool hasAliasAsDefaultProperty() const
996 {
997 return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>();
998 }
999
1000 void setHasAliasAsDefaultProperty(bool defaultAlias)
1001 {
1002 flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias);
1003 }
1004
1005 qint32 objectId() const
1006 {
1007 return flagsAndDefaultPropertyIsAliasAndId.get<IdField>();
1008 }
1009
1010 void setObjectId(qint32 id)
1011 {
1012 flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id);
1013 }
1014
1015
1016 static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
1017 {
1018 return ( sizeof(Object)
1019 + nFunctions * sizeof(quint32)
1020 + nProperties * sizeof(Property)
1021 + nAliases * sizeof(Alias)
1022 + nEnums * sizeof(quint32)
1023 + nSignals * sizeof(quint32)
1024 + nBindings * sizeof(Binding)
1025 + nNamedObjectsInComponent * sizeof(int)
1026 + nInlineComponents * sizeof(InlineComponent)
1027 + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
1028 + 0x7
1029 ) & ~0x7;
1030 }
1031
1032 const quint32_le *functionOffsetTable() const
1033 {
1034 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
1035 }
1036
1037 const Property *propertyTable() const
1038 {
1039 return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
1040 }
1041
1042 const Alias *aliasTable() const
1043 {
1044 return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
1045 }
1046
1047 const Binding *bindingTable() const
1048 {
1049 return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
1050 }
1051
1052 const Enum *enumAt(int idx) const
1053 {
1054 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
1055 const quint32_le offset = offsetTable[idx];
1056 return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
1057 }
1058
1059 const Signal *signalAt(int idx) const
1060 {
1061 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
1062 const quint32_le offset = offsetTable[idx];
1063 return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
1064 }
1065
1066 const InlineComponent *inlineComponentAt(int idx) const
1067 {
1068 return inlineComponentTable() + idx;
1069 }
1070
1071 const quint32_le *namedObjectsInComponentTable() const
1072 {
1073 return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
1074 }
1075
1076 const InlineComponent *inlineComponentTable() const
1077 {
1078 return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
1079 }
1080
1081 const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const
1082 {
1083 return requiredPropertyExtraDataTable() + idx;
1084 }
1085
1086 const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const
1087 {
1088 return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
1089 }
1090
1091 // --- QQmlPropertyCacheCreator interface
1092 int propertyCount() const { return nProperties; }
1093 int aliasCount() const { return nAliases; }
1094 int enumCount() const { return nEnums; }
1095 int signalCount() const { return nSignals; }
1096 int functionCount() const { return nFunctions; }
1097
1098 const Binding *bindingsBegin() const { return bindingTable(); }
1099 const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
1100 int bindingCount() const { return nBindings; }
1101
1102 const Property *propertiesBegin() const { return propertyTable(); }
1103 const Property *propertiesEnd() const { return propertyTable() + nProperties; }
1104
1105 const Alias *aliasesBegin() const { return aliasTable(); }
1106 const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
1107
1108 typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator;
1109 EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
1110 EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
1111
1112 typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
1113 SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
1114 SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
1115
1116 typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator;
1117 InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
1118 InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
1119
1120 typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator;
1121 RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); }
1122 RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }
1123
1124 int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
1125 // ---
1126};
1127static_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");
1128
1129struct Import
1130{
1131 enum ImportType : unsigned int {
1132 ImportLibrary = 0x1,
1133 ImportFile = 0x2,
1134 ImportScript = 0x3,
1135 ImportInlineComponent = 0x4
1136 };
1137 quint32_le type;
1138
1139 quint32_le uriIndex;
1140 quint32_le qualifierIndex;
1141
1142 Location location;
1143 QTypeRevision version;
1144 quint16_le reserved;
1145
1146 Import()
1147 {
1148 type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0;
1149 }
1150};
1151static_assert(sizeof(Import) == 20, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
1152
1153struct QmlUnit
1154{
1155 quint32_le nImports;
1156 quint32_le offsetToImports;
1157 quint32_le nObjects;
1158 quint32_le offsetToObjects;
1159
1160 const Import *importAt(int idx) const {
1161 return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
1162 }
1163
1164 const Object *objectAt(int idx) const {
1165 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
1166 const quint32_le offset = offsetTable[idx];
1167 return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
1168 }
1169};
1170static_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");
1171
1172enum { QmlCompileHashSpace = 48 };
1173static const char magic_str[] = "qv4cdata";
1174
1175struct Unit
1176{
1177 // DO NOT CHANGE THESE FIELDS EVER
1178 char magic[8];
1179 quint32_le version;
1180 quint32_le qtVersion;
1181 qint64_le sourceTimeStamp;
1182 quint32_le unitSize; // Size of the Unit and any depending data.
1183 // END DO NOT CHANGE THESE FIELDS EVER
1184
1185 char libraryVersionHash[QmlCompileHashSpace];
1186
1187 char md5Checksum[16]; // checksum of all bytes following this field.
1188 char dependencyMD5Checksum[16];
1189
1190 enum : unsigned int {
1191 IsJavascript = 0x1,
1192 StaticData = 0x2, // Unit data persistent in memory?
1193 IsSingleton = 0x4,
1194 IsSharedLibrary = 0x8, // .pragma shared?
1195 IsESModule = 0x10,
1196 PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation
1197 IsStrict = 0x40,
1198 ListPropertyAssignReplaceIfDefault = 0x80,
1199 ListPropertyAssignReplaceIfNotDefault = 0x100,
1200 ListPropertyAssignReplace
1201 = ListPropertyAssignReplaceIfDefault | ListPropertyAssignReplaceIfNotDefault,
1202 ComponentsBound = 0x200,
1203 FunctionSignaturesEnforced = 0x400,
1204 NativeMethodsAcceptThisObject = 0x800,
1205 ValueTypesCopied = 0x1000,
1206 ValueTypesAddressable = 0x2000,
1207 };
1208 quint32_le flags;
1209 quint32_le stringTableSize;
1210 quint32_le offsetToStringTable;
1211 quint32_le functionTableSize;
1212 quint32_le offsetToFunctionTable;
1213 quint32_le classTableSize;
1214 quint32_le offsetToClassTable;
1215 quint32_le templateObjectTableSize;
1216 quint32_le offsetToTemplateObjectTable;
1217 quint32_le blockTableSize;
1218 quint32_le offsetToBlockTable;
1219 quint32_le lookupTableSize;
1220 quint32_le offsetToLookupTable;
1221 quint32_le regexpTableSize;
1222 quint32_le offsetToRegexpTable;
1223 quint32_le constantTableSize;
1224 quint32_le offsetToConstantTable;
1225 quint32_le jsClassTableSize;
1226 quint32_le offsetToJSClassTable;
1227 quint32_le translationTableSize;
1228 quint32_le offsetToTranslationTable;
1229 quint32_le localExportEntryTableSize;
1230 quint32_le offsetToLocalExportEntryTable;
1231 quint32_le indirectExportEntryTableSize;
1232 quint32_le offsetToIndirectExportEntryTable;
1233 quint32_le starExportEntryTableSize;
1234 quint32_le offsetToStarExportEntryTable;
1235 quint32_le importEntryTableSize;
1236 quint32_le offsetToImportEntryTable;
1237 quint32_le moduleRequestTableSize;
1238 quint32_le offsetToModuleRequestTable;
1239 qint32_le indexOfRootFunction;
1240 quint32_le sourceFileIndex;
1241 quint32_le finalUrlIndex;
1242
1243 quint32_le offsetToQmlUnit;
1244
1245 /* QML specific fields */
1246
1247 const QmlUnit *qmlUnit() const {
1248 return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
1249 }
1250
1251 QmlUnit *qmlUnit() {
1252 return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
1253 }
1254
1255 bool isSingleton() const {
1256 return flags & Unit::IsSingleton;
1257 }
1258 /* end QML specific fields*/
1259
1260 QString stringAtInternal(uint idx) const {
1261 Q_ASSERT(idx < stringTableSize);
1262 const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
1263 const quint32_le offset = offsetTable[idx];
1264 const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
1265 Q_ASSERT(str->size >= 0);
1266 if (str->size == 0)
1267 return QString();
1268#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1269 const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
1270 if (flags & StaticData)
1271 return QString::fromRawData(characters, size: str->size);
1272 return QString(characters, str->size);
1273#else
1274 const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
1275 QString qstr(str->size, Qt::Uninitialized);
1276 QChar *ch = qstr.data();
1277 for (int i = 0; i < str->size; ++i)
1278 ch[i] = QChar(characters[i]);
1279 return qstr;
1280#endif
1281 }
1282
1283 const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
1284 const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
1285 const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
1286 const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
1287
1288 const Function *functionAt(int idx) const {
1289 const quint32_le *offsetTable = functionOffsetTable();
1290 const quint32_le offset = offsetTable[idx];
1291 return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
1292 }
1293
1294 const Class *classAt(int idx) const {
1295 const quint32_le *offsetTable = classOffsetTable();
1296 const quint32_le offset = offsetTable[idx];
1297 return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
1298 }
1299
1300 const TemplateObject *templateObjectAt(int idx) const {
1301 const quint32_le *offsetTable = templateObjectOffsetTable();
1302 const quint32_le offset = offsetTable[idx];
1303 return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
1304 }
1305
1306 const Block *blockAt(int idx) const {
1307 const quint32_le *offsetTable = blockOffsetTable();
1308 const quint32_le offset = offsetTable[idx];
1309 return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
1310 }
1311
1312 const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
1313 const RegExp *regexpAt(int index) const {
1314 return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
1315 }
1316 const quint64_le *constants() const {
1317 return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
1318 }
1319
1320 const JSClassMember *jsClassAt(int idx, int *nMembers) const {
1321 const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
1322 const quint32_le offset = offsetTable[idx];
1323 const char *ptr = reinterpret_cast<const char *>(this) + offset;
1324 const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
1325 *nMembers = klass->nMembers;
1326 return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
1327 }
1328
1329 const TranslationData *translations() const {
1330 return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
1331 }
1332
1333 const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
1334 const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
1335 const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
1336 const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
1337
1338 const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
1339};
1340
1341static_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");
1342
1343struct TypeReference
1344{
1345 TypeReference(const Location &loc)
1346 : location(loc)
1347 , needsCreation(false)
1348 , errorWhenNotFound(false)
1349 {}
1350 Location location; // first use
1351 bool needsCreation : 1; // whether the type needs to be creatable or not
1352 bool errorWhenNotFound: 1;
1353};
1354
1355// Map from name index to location of first use.
1356struct TypeReferenceMap : QHash<int, TypeReference>
1357{
1358 TypeReference &add(int nameIndex, const Location &loc) {
1359 Iterator it = find(key: nameIndex);
1360 if (it != end())
1361 return *it;
1362 return *insert(key: nameIndex, value: loc);
1363 }
1364
1365 template <typename CompiledObject>
1366 void collectFromObject(const CompiledObject *obj)
1367 {
1368 if (obj->inheritedTypeNameIndex != 0) {
1369 TypeReference &r = this->add(nameIndex: obj->inheritedTypeNameIndex, loc: obj->location);
1370 r.needsCreation = true;
1371 r.errorWhenNotFound = true;
1372 }
1373
1374 auto prop = obj->propertiesBegin();
1375 auto const propEnd = obj->propertiesEnd();
1376 for ( ; prop != propEnd; ++prop) {
1377 if (!prop->isCommonType()) {
1378 TypeReference &r = this->add(nameIndex: prop->commonTypeOrTypeNameIndex(), loc: prop->location);
1379 r.errorWhenNotFound = true;
1380 }
1381 }
1382
1383 auto binding = obj->bindingsBegin();
1384 auto const bindingEnd = obj->bindingsEnd();
1385 for ( ; binding != bindingEnd; ++binding) {
1386 if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty)
1387 this->add(nameIndex: binding->propertyNameIndex, loc: binding->location);
1388 }
1389
1390 auto ic = obj->inlineComponentsBegin();
1391 auto const icEnd = obj->inlineComponentsEnd();
1392 for (; ic != icEnd; ++ic) {
1393 this->add(nameIndex: ic->nameIndex, loc: ic->location);
1394 }
1395 }
1396
1397 template <typename Iterator>
1398 void collectFromObjects(Iterator it, Iterator end)
1399 {
1400 for (; it != end; ++it)
1401 collectFromObject(*it);
1402 }
1403};
1404
1405using DependentTypesHasher = std::function<QByteArray()>;
1406
1407// This is how this hooks into the existing structures:
1408
1409struct CompilationUnitBase
1410{
1411 Q_DISABLE_COPY(CompilationUnitBase)
1412
1413 CompilationUnitBase() = default;
1414 ~CompilationUnitBase() = default;
1415
1416 CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); }
1417
1418 CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept
1419 {
1420 if (this != &other) {
1421 runtimeStrings = other.runtimeStrings;
1422 other.runtimeStrings = nullptr;
1423 constants = other.constants;
1424 other.constants = nullptr;
1425 runtimeRegularExpressions = other.runtimeRegularExpressions;
1426 other.runtimeRegularExpressions = nullptr;
1427 runtimeClasses = other.runtimeClasses;
1428 other.runtimeClasses = nullptr;
1429 imports = other.imports;
1430 other.imports = nullptr;
1431 }
1432 return *this;
1433 }
1434
1435 // pointers either to data->constants() or little-endian memory copy.
1436 Heap::String **runtimeStrings = nullptr; // Array
1437 const StaticValue* constants = nullptr;
1438 QV4::StaticValue *runtimeRegularExpressions = nullptr;
1439 Heap::InternalClass **runtimeClasses = nullptr;
1440 const StaticValue** imports = nullptr;
1441};
1442
1443Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
1444Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
1445Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
1446Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
1447Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
1448Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
1449
1450struct CompilationUnit : public CompilationUnitBase
1451{
1452 Q_DISABLE_COPY(CompilationUnit)
1453
1454 const Unit *data = nullptr;
1455 const QmlUnit *qmlData = nullptr;
1456 QStringList dynamicStrings;
1457 const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions = nullptr;
1458public:
1459 using CompiledObject = CompiledData::Object;
1460
1461 CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(),
1462 const QString &finalUrlString = QString())
1463 {
1464 setUnitData(unitData, qmlUnit: nullptr, fileName, finalUrlString);
1465 }
1466
1467 explicit CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions,
1468 const QString &fileName = QString(), const QString &finalUrlString = QString())
1469 : CompilationUnit(unitData, fileName, finalUrlString)
1470 {
1471 this->aotCompiledFunctions = aotCompiledFunctions;
1472 }
1473
1474 ~CompilationUnit()
1475 {
1476 if (data) {
1477 if (data->qmlUnit() != qmlData)
1478 free(ptr: const_cast<QmlUnit *>(qmlData));
1479 qmlData = nullptr;
1480
1481 if (!(data->flags & QV4::CompiledData::Unit::StaticData))
1482 free(ptr: const_cast<Unit *>(data));
1483 }
1484 data = nullptr;
1485#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1486 delete [] constants;
1487 constants = nullptr;
1488#endif
1489
1490 delete [] imports;
1491 imports = nullptr;
1492 }
1493
1494 CompilationUnit(CompilationUnit &&other) noexcept
1495 {
1496 *this = std::move(other);
1497 }
1498
1499 CompilationUnit &operator=(CompilationUnit &&other) noexcept
1500 {
1501 if (this != &other) {
1502 data = other.data;
1503 other.data = nullptr;
1504 qmlData = other.qmlData;
1505 other.qmlData = nullptr;
1506 dynamicStrings = std::move(other.dynamicStrings);
1507 aotCompiledFunctions = other.aotCompiledFunctions;
1508 other.dynamicStrings.clear();
1509 m_fileName = std::move(other.m_fileName);
1510 other.m_fileName.clear();
1511 m_finalUrlString = std::move(other.m_finalUrlString);
1512 other.m_finalUrlString.clear();
1513 m_module = other.m_module;
1514 other.m_module = nullptr;
1515 CompilationUnitBase::operator=(other: std::move(other));
1516 }
1517 return *this;
1518 }
1519
1520 const Unit *unitData() const { return data; }
1521
1522 void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
1523 const QString &fileName = QString(), const QString &finalUrlString = QString())
1524 {
1525 data = unitData;
1526 qmlData = nullptr;
1527#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1528 delete [] constants;
1529#endif
1530 constants = nullptr;
1531 m_fileName.clear();
1532 m_finalUrlString.clear();
1533 if (!data)
1534 return;
1535
1536 qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
1537
1538#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1539 StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
1540 const quint64_le *littleEndianConstants = data->constants();
1541 for (uint i = 0; i < data->constantTableSize; ++i)
1542 bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
1543 constants = bigEndianConstants;
1544#else
1545 constants = reinterpret_cast<const StaticValue*>(data->constants());
1546#endif
1547
1548 m_fileName = !fileName.isEmpty() ? fileName : stringAt(index: data->sourceFileIndex);
1549 m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(index: data->finalUrlIndex);
1550 }
1551
1552 QString stringAt(uint index) const
1553 {
1554 if (index < data->stringTableSize)
1555 return data->stringAtInternal(idx: index);
1556
1557 const qsizetype dynamicIndex = index - data->stringTableSize;
1558 Q_ASSERT(dynamicIndex < dynamicStrings.size());
1559 return dynamicStrings.at(i: dynamicIndex);
1560 }
1561
1562 QString fileName() const { return m_fileName; }
1563 QString finalUrlString() const { return m_finalUrlString; }
1564
1565 Heap::Module *module() const { return m_module; }
1566 void setModule(Heap::Module *module) { m_module = module; }
1567
1568 QString bindingValueAsString(const CompiledData::Binding *binding) const
1569 {
1570 using namespace CompiledData;
1571 switch (binding->type()) {
1572 case Binding::Type_Script:
1573 case Binding::Type_String:
1574 return stringAt(index: binding->stringIndex);
1575 case Binding::Type_Null:
1576 return QStringLiteral("null");
1577 case Binding::Type_Boolean:
1578 return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
1579 case Binding::Type_Number:
1580 return QString::number(bindingValueAsNumber(binding), format: 'g', precision: QLocale::FloatingPointShortest);
1581 case Binding::Type_Invalid:
1582 return QString();
1583 case Binding::Type_TranslationById:
1584 case Binding::Type_Translation:
1585 return stringAt(index: data->translations()[binding->value.translationDataIndex].stringIndex);
1586 default:
1587 break;
1588 }
1589 return QString();
1590 }
1591
1592 QString bindingValueAsScriptString(const CompiledData::Binding *binding) const
1593 {
1594 return (binding->type() == CompiledData::Binding::Type_String)
1595 ? CompiledData::Binding::escapedString(string: stringAt(index: binding->stringIndex))
1596 : bindingValueAsString(binding);
1597 }
1598
1599 double bindingValueAsNumber(const CompiledData::Binding *binding) const
1600 {
1601 if (binding->type() != CompiledData::Binding::Type_Number)
1602 return 0.0;
1603 return constants[binding->value.constantValueIndex].doubleValue();
1604 }
1605
1606private:
1607 QString m_fileName; // initialized from data->sourceFileIndex
1608 QString m_finalUrlString; // initialized from data->finalUrlIndex
1609
1610 Heap::Module *m_module = nullptr;
1611};
1612
1613class SaveableUnitPointer
1614{
1615 Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
1616public:
1617 SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) :
1618 unit(unit),
1619 temporaryFlags(temporaryFlags)
1620 {
1621 }
1622
1623 ~SaveableUnitPointer() = default;
1624
1625 template<typename Char>
1626 bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
1627 {
1628 const quint32_le oldFlags = mutableFlags();
1629 auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
1630 mutableFlags() |= temporaryFlags;
1631 return writer(data<Char>(), size());
1632 }
1633
1634 static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
1635 QString *errorString)
1636 {
1637#if QT_CONFIG(temporaryfile)
1638 QSaveFile cacheFile(outputFileName);
1639 if (!cacheFile.open(flags: QIODevice::WriteOnly | QIODevice::Truncate)
1640 || cacheFile.write(data, len: size) != size
1641 || !cacheFile.commit()) {
1642 *errorString = cacheFile.errorString();
1643 return false;
1644 }
1645
1646 errorString->clear();
1647 return true;
1648#else
1649 Q_UNUSED(outputFileName);
1650 *errorString = QStringLiteral("features.temporaryfile is disabled.");
1651 return false;
1652#endif
1653 }
1654
1655private:
1656 const Unit *unit;
1657 quint32 temporaryFlags;
1658
1659 quint32_le &mutableFlags() const
1660 {
1661 return const_cast<Unit *>(unit)->flags;
1662 }
1663
1664 template<typename Char>
1665 const Char *data() const
1666 {
1667 Q_STATIC_ASSERT(sizeof(Char) == 1);
1668 const Char *dataPtr;
1669 memcpy(&dataPtr, &unit, sizeof(dataPtr));
1670 return dataPtr;
1671 }
1672
1673 quint32 size() const
1674 {
1675 return unit->unitSize;
1676 }
1677};
1678
1679
1680} // CompiledData namespace
1681} // QV4 namespace
1682
1683Q_DECLARE_OPERATORS_FOR_FLAGS(QV4::CompiledData::ParameterType::Flags);
1684Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
1685
1686QT_END_NAMESPACE
1687
1688#endif
1689

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