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

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