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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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