aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/common/qv4compileddata_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/common/qv4compileddata_p.h')
-rw-r--r--src/qml/common/qv4compileddata_p.h1844
1 files changed, 1844 insertions, 0 deletions
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
new file mode 100644
index 0000000000..c21fc19fa9
--- /dev/null
+++ b/src/qml/common/qv4compileddata_p.h
@@ -0,0 +1,1844 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QV4COMPILEDDATA_P_H
+#define QV4COMPILEDDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <functional>
+
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qhashfunctions.h>
+#include <QtCore/qlocale.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qversionnumber.h>
+
+#if QT_CONFIG(temporaryfile)
+#include <QtCore/qsavefile.h>
+#endif
+
+#include <private/qendian_p.h>
+#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlpropertycachevector_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qv4compilationunitmapper_p.h>
+#include <private/qv4staticvalue_p.h>
+
+#include <functional>
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+// Bump this whenever the compiler data structures change in an incompatible way.
+//
+// IMPORTANT:
+//
+// Also change the comment behind the number to describe the latest change. This has the added
+// benefit that if another patch changes the version too, it will result in a merge conflict, and
+// not get removed silently.
+#define QV4_DATA_STRUCTURE_VERSION 0x42 // Change metatype computation of AOT-compiled functions
+
+class QIODevice;
+class QQmlTypeNameCache;
+class QQmlType;
+class QQmlEngine;
+class QQmlPropertyData;
+class QQmlScriptData;
+
+namespace QQmlPrivate {
+struct AOTCompiledFunction;
+}
+
+namespace QmlIR {
+struct Document;
+}
+
+namespace QV4 {
+namespace Heap {
+struct Module;
+struct String;
+struct InternalClass;
+};
+
+struct Function;
+class EvalISelFactory;
+class ResolvedTypeReference;
+
+namespace CompiledData {
+
+// index is per-object binding index
+using BindingPropertyData = QVector<const QQmlPropertyData *>;
+
+// map from name index
+struct ResolvedTypeReferenceMap: public QHash<int, ResolvedTypeReference*>
+{
+ bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const;
+};
+
+struct String;
+struct Function;
+struct Lookup;
+struct RegExp;
+struct Unit;
+
+template <typename ItemType, typename Container, const ItemType *(Container::*IndexedGetter)(int index) const>
+struct TableIterator
+{
+ TableIterator(const Container *container, int index) : container(container), index(index) {}
+ const Container *container;
+ int index;
+
+ const ItemType *operator->() { return (container->*IndexedGetter)(index); }
+ ItemType operator*() {return *operator->();}
+ void operator++() { ++index; }
+ bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
+};
+
+struct Location
+{
+ Location() : m_data(QSpecialIntegerBitfieldZero) {}
+ Location(quint32 l, quint32 c) : Location()
+ {
+ m_data.set<LineField>(l);
+ m_data.set<ColumnField>(c);
+ Q_ASSERT(m_data.get<LineField>() == l);
+ Q_ASSERT(m_data.get<ColumnField>() == c);
+ }
+
+ inline bool operator<(const Location &other) const {
+ return m_data.get<LineField>() < other.m_data.get<LineField>()
+ || (m_data.get<LineField>() == other.m_data.get<LineField>()
+ && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
+ }
+
+ friend size_t qHash(const Location &location, size_t seed = 0)
+ {
+ return QT_PREPEND_NAMESPACE(qHash)(location.m_data.data(), seed);
+ }
+
+ friend bool operator==(const Location &a, const Location &b)
+ {
+ return a.m_data.data()== b.m_data.data();
+ }
+
+ void set(quint32 line, quint32 column)
+ {
+ m_data.set<LineField>(line);
+ m_data.set<ColumnField>(column);
+ }
+
+ quint32 line() const { return m_data.get<LineField>(); }
+ quint32 column() const { return m_data.get<ColumnField>(); }
+
+private:
+ using LineField = quint32_le_bitfield_member<0, 20>;
+ using ColumnField = quint32_le_bitfield_member<20, 12>;
+
+ quint32_le_bitfield_union<LineField, ColumnField> m_data;
+};
+static_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");
+
+struct RegExp
+{
+ enum Flags : unsigned int {
+ RegExp_NoFlags = 0x0,
+ RegExp_Global = 0x01,
+ RegExp_IgnoreCase = 0x02,
+ RegExp_Multiline = 0x04,
+ RegExp_Sticky = 0x08,
+ RegExp_Unicode = 0x10,
+ };
+
+ RegExp() : m_data(QSpecialIntegerBitfieldZero) {}
+ RegExp(quint32 flags, quint32 stringIndex) : RegExp()
+ {
+ m_data.set<FlagsField>(flags);
+ m_data.set<StringIndexField>(stringIndex);
+ }
+
+ quint32 flags() const { return m_data.get<FlagsField>(); }
+ quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
+
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 5>;
+ using StringIndexField = quint32_le_bitfield_member<5, 27>;
+ quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
+};
+static_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");
+
+struct Lookup
+{
+ enum Type : unsigned int {
+ Type_Getter = 0,
+ Type_Setter = 1,
+ Type_GlobalGetter = 2,
+ Type_QmlContextPropertyGetter = 3
+ };
+
+ enum Mode : unsigned int {
+ Mode_ForStorage = 0,
+ Mode_ForCall = 1
+ };
+
+ quint32 type() const { return m_data.get<TypeField>(); }
+ quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
+ quint32 mode() const { return m_data.get<ModeField>(); }
+
+ Lookup() : m_data(QSpecialIntegerBitfieldZero) {}
+ Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup()
+ {
+ m_data.set<TypeField>(type);
+ m_data.set<ModeField>(mode);
+ m_data.set<NameIndexField>(nameIndex);
+ }
+
+private:
+ using TypeField = quint32_le_bitfield_member<0, 2>;
+ using ModeField = quint32_le_bitfield_member<2, 1>;
+ // 1 bit left
+ using NameIndexField = quint32_le_bitfield_member<4, 28>;
+ quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data;
+};
+static_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");
+
+struct JSClassMember
+{
+ JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {}
+
+ void set(quint32 nameOffset, bool isAccessor)
+ {
+ m_data.set<NameOffsetField>(nameOffset);
+ m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
+ }
+
+ quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
+ bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
+
+private:
+ using NameOffsetField = quint32_le_bitfield_member<0, 31>;
+ using IsAccessorField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
+};
+static_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");
+
+struct JSClass
+{
+ quint32_le nMembers;
+ // JSClassMember[nMembers]
+
+ static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
+};
+static_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");
+
+struct String
+{
+ qint32_le size;
+
+ static int calculateSize(const QString &str) {
+ // we cannot enconuter strings larger than INT_MAX anyway, as such a string
+ // would already break in other parts of the compilation process
+ return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7;
+ }
+};
+
+static_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");
+
+struct CodeOffsetToLineAndStatement {
+ quint32_le codeOffset;
+ qint32_le line; // signed because debug instructions get negative line numbers
+ quint32_le statement;
+};
+static_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");
+
+struct Block
+{
+ quint32_le nLocals;
+ quint32_le localsOffset;
+ quint16_le sizeOfLocalTemporalDeadZone;
+ quint16_le padding;
+
+ const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
+
+ static int calculateSize(int nLocals) {
+ int trailingData = nLocals*sizeof (quint32);
+ size_t size = align(align(sizeof(Block)) + size_t(trailingData));
+ Q_ASSERT(size < INT_MAX);
+ return int(size);
+ }
+
+ static size_t align(size_t a) {
+ return (a + 7) & ~size_t(7);
+ }
+};
+static_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");
+
+enum class NamedBuiltin: unsigned int {
+ Void, Var, Int, Bool, Real, String, Url, DateTime, RegExp
+};
+
+enum class CommonType : unsigned int {
+ // Actual named builtins
+ Void = uint(NamedBuiltin::Void),
+ Var = uint(NamedBuiltin::Var),
+ Int = uint(NamedBuiltin::Int),
+ Bool = uint(NamedBuiltin::Bool),
+ Real = uint(NamedBuiltin::Real),
+ String = uint(NamedBuiltin::String),
+ Url = uint(NamedBuiltin::Url),
+ DateTime = uint(NamedBuiltin::DateTime),
+ RegExp = uint(NamedBuiltin::RegExp),
+
+ // Optimization for very common other types
+ Time, Date, Rect, Point, Size,
+
+ // No type specified or not recognized
+ Invalid
+};
+
+struct ParameterType
+{
+ enum Flag {
+ NoFlag = 0x0,
+ Common = 0x1,
+ List = 0x2,
+ };
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ void set(Flags flags, quint32 typeNameIndexOrCommonType)
+ {
+ m_data.set<IsListField>(flags.testFlag(List) ? 1 : 0);
+ m_data.set<IndexIsCommonTypeField>(flags.testFlag(Common) ? 1 : 0);
+ m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType);
+ }
+
+ bool indexIsCommonType() const
+ {
+ return m_data.get<IndexIsCommonTypeField>() != 0;
+ }
+
+ bool isList() const
+ {
+ return m_data.get<IsListField>() != 0;
+ }
+
+ quint32 typeNameIndexOrCommonType() const
+ {
+ return m_data.get<TypeNameIndexOrCommonTypeField>();
+ }
+
+private:
+ using IndexIsCommonTypeField = quint32_le_bitfield_member<0, 1>;
+ using IsListField = quint32_le_bitfield_member<1, 1>;
+ using TypeNameIndexOrCommonTypeField = quint32_le_bitfield_member<2, 30>;
+ quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data;
+};
+static_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");
+
+struct Parameter
+{
+ quint32_le nameIndex;
+ ParameterType type;
+};
+static_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");
+
+// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
+// for unaligned access. The ordering of the fields is also from largest to smallest.
+struct Function
+{
+ enum Flags : unsigned int {
+ IsStrict = 0x1,
+ IsArrowFunction = 0x2,
+ IsGenerator = 0x4,
+ IsClosureWrapper = 0x8,
+ };
+
+ // Absolute offset into file where the code for this function is located.
+ quint32_le codeOffset;
+ quint32_le codeSize;
+
+ quint32_le nameIndex;
+ quint16_le length;
+ quint16_le nFormals;
+ quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
+ ParameterType returnType;
+ quint32_le localsOffset;
+ quint16_le nLocals;
+ quint16_le nLineAndStatementNumbers;
+ size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
+ quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
+
+ quint32_le nRegisters;
+ Location location;
+ quint32_le nLabelInfos;
+
+ quint16_le sizeOfLocalTemporalDeadZone;
+ quint16_le firstTemporalDeadZoneRegister;
+ quint16_le sizeOfRegisterTemporalDeadZone;
+
+ size_t labelInfosOffset() const
+ {
+ return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement);
+ }
+
+ // Keep all unaligned data at the end
+ quint8 flags;
+ quint8 padding1;
+
+ // quint32 formalsIndex[nFormals]
+ // quint32 localsIndex[nLocals]
+
+ const Parameter *formalsTable() const
+ {
+ return reinterpret_cast<const Parameter *>(
+ reinterpret_cast<const char *>(this) + formalsOffset);
+ }
+ const quint32_le *localsTable() const
+ {
+ return reinterpret_cast<const quint32_le *>(
+ reinterpret_cast<const char *>(this) + localsOffset);
+ }
+ const CodeOffsetToLineAndStatement *lineAndStatementNumberTable() const
+ {
+ return reinterpret_cast<const CodeOffsetToLineAndStatement *>(
+ reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset());
+ }
+
+ // --- QQmlPropertyCacheCreator interface
+ const Parameter *formalsBegin() const { return formalsTable(); }
+ const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
+ // ---
+
+ const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
+
+ const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
+
+ static int calculateSize(
+ int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions,
+ int labelInfoSize, int codeSize)
+ {
+ int trailingData = nFormals * sizeof(Parameter)
+ + (nLocals + nInnerfunctions + labelInfoSize) * sizeof (quint32)
+ + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement);
+ size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
+ Q_ASSERT(size < INT_MAX);
+ return int(size);
+ }
+
+ static size_t align(size_t a) {
+ return (a + 7) & ~size_t(7);
+ }
+};
+static_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");
+
+struct Method {
+ enum Type {
+ Regular,
+ Getter,
+ Setter
+ };
+
+ quint32_le name;
+ quint32_le type;
+ quint32_le function;
+};
+static_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");
+
+struct Class
+{
+ quint32_le nameIndex;
+ quint32_le scopeIndex;
+ quint32_le constructorFunction;
+ quint32_le nStaticMethods;
+ quint32_le nMethods;
+ quint32_le methodTableOffset;
+
+ const Method *methodTable() const { return reinterpret_cast<const Method *>(reinterpret_cast<const char *>(this) + methodTableOffset); }
+
+ static int calculateSize(int nStaticMethods, int nMethods) {
+ int trailingData = (nStaticMethods + nMethods) * sizeof(Method);
+ size_t size = align(sizeof(Class) + trailingData);
+ Q_ASSERT(size < INT_MAX);
+ return int(size);
+ }
+
+ static size_t align(size_t a) {
+ return (a + 7) & ~size_t(7);
+ }
+};
+static_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");
+
+struct TemplateObject
+{
+ quint32_le size;
+
+ static int calculateSize(int size) {
+ int trailingData = 2 * size * sizeof(quint32_le);
+ size_t s = align(sizeof(TemplateObject) + trailingData);
+ Q_ASSERT(s < INT_MAX);
+ return int(s);
+ }
+
+ static size_t align(size_t a) {
+ return (a + 7) & ~size_t(7);
+ }
+
+ const quint32_le *stringTable() const {
+ return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this + 1));
+ }
+
+ uint stringIndexAt(uint i) const {
+ return stringTable()[i];
+ }
+ uint rawStringIndexAt(uint i) const {
+ return stringTable()[size + i];
+ }
+};
+static_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");
+
+struct ExportEntry
+{
+ quint32_le exportName;
+ quint32_le moduleRequest;
+ quint32_le importName;
+ quint32_le localName;
+ Location location;
+};
+static_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");
+
+struct ImportEntry
+{
+ quint32_le moduleRequest;
+ quint32_le importName;
+ quint32_le localName;
+ Location location;
+};
+static_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");
+
+// Qml data structures
+
+struct TranslationData
+{
+ enum { NoContextIndex = std::numeric_limits<quint32>::max() };
+ quint32_le stringIndex;
+ quint32_le commentIndex;
+ qint32_le number;
+ quint32_le contextIndex;
+};
+static_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");
+
+struct Binding
+{
+ quint32_le propertyNameIndex;
+
+ enum Type : unsigned int {
+ Type_Invalid,
+ Type_Boolean,
+ Type_Number,
+ Type_String,
+ Type_Null,
+ Type_Translation,
+ Type_TranslationById,
+ Type_Script,
+ Type_Object,
+ Type_AttachedProperty,
+ Type_GroupProperty
+ };
+
+ enum Flag : unsigned int {
+ IsSignalHandlerExpression = 0x1,
+ IsSignalHandlerObject = 0x2,
+ IsOnAssignment = 0x4,
+ InitializerForReadOnlyDeclaration = 0x8,
+ IsResolvedEnum = 0x10,
+ IsListItem = 0x20,
+ IsBindingToAlias = 0x40,
+ IsDeferredBinding = 0x80,
+ IsCustomParserBinding = 0x100,
+ IsFunctionExpression = 0x200,
+ IsPropertyObserver = 0x400
+ };
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ using FlagsField = quint32_le_bitfield_member<0, 16>;
+ using TypeField = quint32_le_bitfield_member<16, 16>;
+ quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType;
+
+ void clearFlags() { flagsAndType.set<FlagsField>(0); }
+ void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
+ bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
+ Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
+
+ void setType(Type type) { flagsAndType.set<TypeField>(type); }
+ Type type() const { return Type(flagsAndType.get<TypeField>()); }
+
+ union {
+ bool b;
+ quint32_le constantValueIndex;
+ quint32_le compiledScriptIndex; // used when Type_Script
+ quint32_le objectIndex;
+ quint32_le translationDataIndex; // used when Type_Translation
+ quint32 nullMarker;
+ } value;
+ quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
+
+ Location location;
+ Location valueLocation;
+
+ bool hasSignalHandlerBindingFlag() const
+ {
+ const Flags bindingFlags = flags();
+ return bindingFlags & IsSignalHandlerExpression
+ || bindingFlags & IsSignalHandlerObject
+ || bindingFlags & IsPropertyObserver;
+ }
+
+ bool isValueBinding() const
+ {
+ switch (type()) {
+ case Type_AttachedProperty:
+ case Type_GroupProperty:
+ return false;
+ default:
+ return !hasSignalHandlerBindingFlag();
+ }
+ }
+
+ bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(IsBindingToAlias); }
+ bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(IsBindingToAlias); }
+
+ bool isSignalHandler() const
+ {
+ if (hasSignalHandlerBindingFlag()) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isAttachedProperty());
+ Q_ASSERT(!isGroupProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isAttachedProperty() const
+ {
+ if (type() == Type_AttachedProperty) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isSignalHandler());
+ Q_ASSERT(!isGroupProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isGroupProperty() const
+ {
+ if (type() == Type_GroupProperty) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isSignalHandler());
+ Q_ASSERT(!isAttachedProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isFunctionExpression() const { return hasFlag(IsFunctionExpression); }
+
+ //reverse of Lexer::singleEscape()
+ static QString escapedString(const QString &string)
+ {
+ QString tmp = QLatin1String("\"");
+ for (int i = 0; i < string.size(); ++i) {
+ const QChar &c = string.at(i);
+ switch (c.unicode()) {
+ case 0x08:
+ tmp += QLatin1String("\\b");
+ break;
+ case 0x09:
+ tmp += QLatin1String("\\t");
+ break;
+ case 0x0A:
+ tmp += QLatin1String("\\n");
+ break;
+ case 0x0B:
+ tmp += QLatin1String("\\v");
+ break;
+ case 0x0C:
+ tmp += QLatin1String("\\f");
+ break;
+ case 0x0D:
+ tmp += QLatin1String("\\r");
+ break;
+ case 0x22:
+ tmp += QLatin1String("\\\"");
+ break;
+ case 0x27:
+ tmp += QLatin1String("\\\'");
+ break;
+ case 0x5C:
+ tmp += QLatin1String("\\\\");
+ break;
+ default:
+ tmp += c;
+ break;
+ }
+ }
+ tmp += QLatin1Char('\"');
+ return tmp;
+ }
+
+ bool isTranslationBinding() const
+ {
+ const Binding::Type bindingType = type();
+ return bindingType == Type_Translation || bindingType == Type_TranslationById;
+ }
+ bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); }
+
+ bool isNumberBinding() const { return type() == Type_Number; }
+
+ bool valueAsBoolean() const
+ {
+ if (type() == Type_Boolean)
+ return value.b;
+ return false;
+ }
+};
+
+static_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");
+
+struct InlineComponent
+{
+ quint32_le objectIndex;
+ quint32_le nameIndex;
+ Location location;
+};
+
+static_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");
+
+struct EnumValue
+{
+ quint32_le nameIndex;
+ qint32_le value;
+ Location location;
+};
+static_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");
+
+struct Enum
+{
+ quint32_le nameIndex;
+ quint32_le nEnumValues;
+ Location location;
+
+ const EnumValue *enumValueAt(int idx) const {
+ return reinterpret_cast<const EnumValue*>(this + 1) + idx;
+ }
+
+ static int calculateSize(int nEnumValues) {
+ return (sizeof(Enum)
+ + nEnumValues * sizeof(EnumValue)
+ + 7) & ~0x7;
+ }
+
+ // --- QQmlPropertyCacheCreatorInterface
+ const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
+ const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
+ int enumValueCount() const { return nEnumValues; }
+ // ---
+};
+static_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");
+
+struct Signal
+{
+ quint32_le nameIndex;
+ quint32_le nParameters;
+ Location location;
+ // Parameter parameters[1];
+
+ const Parameter *parameterAt(int idx) const {
+ return reinterpret_cast<const Parameter*>(this + 1) + idx;
+ }
+
+ static int calculateSize(int nParameters) {
+ return (sizeof(Signal)
+ + nParameters * sizeof(Parameter)
+ + 7) & ~0x7;
+ }
+
+ // --- QQmlPropertyCacheCceatorInterface
+ const Parameter *parametersBegin() const { return parameterAt(0); }
+ const Parameter *parametersEnd() const { return parameterAt(nParameters); }
+ int parameterCount() const { return nParameters; }
+ // ---
+};
+static_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");
+
+struct Property
+{
+private:
+ using CommonTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>;
+ using IsRequiredField = quint32_le_bitfield_member<28, 1>;
+ using IsCommonTypeField = quint32_le_bitfield_member<29, 1>;
+ using IsListField = quint32_le_bitfield_member<30, 1>;
+ using IsReadOnlyField = quint32_le_bitfield_member<31, 1>;
+
+public:
+ quint32_le nameIndex;
+ quint32_le_bitfield_union<
+ CommonTypeOrTypeNameIndexField,
+ IsRequiredField,
+ IsCommonTypeField,
+ IsListField,
+ IsReadOnlyField> data;
+ Location location;
+
+ void setCommonType(CommonType t)
+ {
+ data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t));
+ data.set<IsCommonTypeField>(true);
+ }
+
+ CommonType commonType() const {
+ if (data.get<IsCommonTypeField>() != 0)
+ return CommonType(data.get<CommonTypeOrTypeNameIndexField>());
+ return CommonType::Invalid;
+ }
+
+ void setTypeNameIndex(int nameIndex)
+ {
+ data.set<CommonTypeOrTypeNameIndexField>(nameIndex);
+ data.set<IsCommonTypeField>(false);
+ }
+
+ int typeNameIndex() const
+ {
+ return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>();
+ }
+
+ bool isCommonType() const { return data.get<IsCommonTypeField>(); }
+ uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); }
+
+ bool isList() const { return data.get<IsListField>(); }
+ void setIsList(bool isList) { data.set<IsListField>(isList); }
+
+ bool isRequired() const { return data.get<IsRequiredField>(); }
+ void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
+
+ bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
+ void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
+};
+static_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");
+
+struct RequiredPropertyExtraData {
+ quint32_le nameIndex;
+};
+
+static_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");
+
+struct Alias {
+private:
+ using NameIndexField = quint32_le_bitfield_member<0, 29>;
+ using FlagsField = quint32_le_bitfield_member<29, 3>;
+
+ // object id index (in QQmlContextData::idValues)
+ using TargetObjectIdField = quint32_le_bitfield_member<0, 31>;
+ using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>;
+ using IdIndexField = quint32_le_bitfield_member<0, 32>;
+
+public:
+
+ enum Flag : unsigned int {
+ IsReadOnly = 0x1,
+ Resolved = 0x2,
+ AliasPointsToPointerObject = 0x4
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags;
+ quint32_le_bitfield_union<IdIndexField, TargetObjectIdField, AliasToLocalAliasField>
+ idIndexAndTargetObjectIdAndAliasToLocalAlias;
+
+ union {
+ quint32_le propertyNameIndex; // string index
+ qint32_le encodedMetaPropertyIndex;
+ quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
+ };
+ Location location;
+ Location referenceLocation;
+
+ bool hasFlag(Flag flag) const
+ {
+ return nameIndexAndFlags.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag);
+ }
+
+ void clearFlags()
+ {
+ nameIndexAndFlags.set<FlagsField>(0);
+ }
+
+ quint32 nameIndex() const
+ {
+ return nameIndexAndFlags.get<NameIndexField>();
+ }
+
+ void setNameIndex(quint32 nameIndex)
+ {
+ nameIndexAndFlags.set<NameIndexField>(nameIndex);
+ }
+
+ bool isObjectAlias() const
+ {
+ Q_ASSERT(hasFlag(Resolved));
+ return encodedMetaPropertyIndex == -1;
+ }
+
+ quint32 idIndex() const
+ {
+ return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<IdIndexField>();
+ }
+
+ void setIdIndex(quint32 idIndex)
+ {
+ idIndexAndTargetObjectIdAndAliasToLocalAlias.set<IdIndexField>(idIndex);
+ }
+
+
+ bool isAliasToLocalAlias() const
+ {
+ return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>();
+ }
+
+ void setIsAliasToLocalAlias(bool isAliasToLocalAlias)
+ {
+ idIndexAndTargetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias);
+ }
+
+ quint32 targetObjectId() const
+ {
+ return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>();
+ }
+
+ void setTargetObjectId(quint32 targetObjectId)
+ {
+ idIndexAndTargetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId);
+ }
+};
+static_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");
+
+struct Object
+{
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 15>;
+ using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>;
+ using IdField = quint32_le_bitfield_member<16, 16, qint32>;
+public:
+ enum Flag : unsigned int {
+ NoFlag = 0x0,
+ IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
+ HasDeferredBindings = 0x2, // any of the bindings are deferred
+ HasCustomParserBindings = 0x4,
+ IsInlineComponentRoot = 0x8,
+ IsPartOfInlineComponent = 0x10
+ };
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ // Depending on the use, this may be the type name to instantiate before instantiating this
+ // object. For grouped properties the type name will be empty and for attached properties
+ // it will be the name of the attached type.
+ quint32_le inheritedTypeNameIndex;
+ quint32_le idNameIndex;
+ quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField>
+ flagsAndDefaultPropertyIsAliasAndId;
+ qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
+ quint16_le nFunctions;
+ quint16_le nProperties;
+ quint32_le offsetToFunctions;
+ quint32_le offsetToProperties;
+ quint32_le offsetToAliases;
+ quint16_le nAliases;
+ quint16_le nEnums;
+ quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
+ quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
+ quint16_le nSignals;
+ quint16_le nBindings;
+ quint32_le offsetToBindings;
+ quint32_le nNamedObjectsInComponent;
+ quint32_le offsetToNamedObjectsInComponent;
+ Location location;
+ Location locationOfIdProperty;
+ quint32_le offsetToInlineComponents;
+ quint16_le nInlineComponents;
+ quint32_le offsetToRequiredPropertyExtraData;
+ quint16_le nRequiredPropertyExtraData;
+// Function[]
+// Property[]
+// Signal[]
+// Binding[]
+// InlineComponent[]
+// RequiredPropertyExtraData[]
+
+ Flags flags() const
+ {
+ return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>());
+ }
+
+ bool hasFlag(Flag flag) const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(
+ flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag);
+ }
+
+ void setFlags(Flags flags)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags);
+ }
+
+ bool hasAliasAsDefaultProperty() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>();
+ }
+
+ void setHasAliasAsDefaultProperty(bool defaultAlias)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias);
+ }
+
+ qint32 objectId() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<IdField>();
+ }
+
+ void setObjectId(qint32 id)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id);
+ }
+
+
+ static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
+ {
+ return ( sizeof(Object)
+ + nFunctions * sizeof(quint32)
+ + nProperties * sizeof(Property)
+ + nAliases * sizeof(Alias)
+ + nEnums * sizeof(quint32)
+ + nSignals * sizeof(quint32)
+ + nBindings * sizeof(Binding)
+ + nNamedObjectsInComponent * sizeof(int)
+ + nInlineComponents * sizeof(InlineComponent)
+ + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
+ + 0x7
+ ) & ~0x7;
+ }
+
+ const quint32_le *functionOffsetTable() const
+ {
+ return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
+ }
+
+ const Property *propertyTable() const
+ {
+ return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
+ }
+
+ const Alias *aliasTable() const
+ {
+ return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
+ }
+
+ const Binding *bindingTable() const
+ {
+ return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
+ }
+
+ const Enum *enumAt(int idx) const
+ {
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
+ }
+
+ const Signal *signalAt(int idx) const
+ {
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
+ }
+
+ const InlineComponent *inlineComponentAt(int idx) const
+ {
+ return inlineComponentTable() + idx;
+ }
+
+ const quint32_le *namedObjectsInComponentTable() const
+ {
+ return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
+ }
+
+ const InlineComponent *inlineComponentTable() const
+ {
+ return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
+ }
+
+ const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const
+ {
+ return requiredPropertyExtraDataTable() + idx;
+ }
+
+ const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const
+ {
+ return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
+ }
+
+ // --- QQmlPropertyCacheCreator interface
+ int propertyCount() const { return nProperties; }
+ int aliasCount() const { return nAliases; }
+ int enumCount() const { return nEnums; }
+ int signalCount() const { return nSignals; }
+ int functionCount() const { return nFunctions; }
+
+ const Binding *bindingsBegin() const { return bindingTable(); }
+ const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
+ int bindingCount() const { return nBindings; }
+
+ const Property *propertiesBegin() const { return propertyTable(); }
+ const Property *propertiesEnd() const { return propertyTable() + nProperties; }
+
+ const Alias *aliasesBegin() const { return aliasTable(); }
+ const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
+
+ typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator;
+ EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
+ EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
+
+ typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
+ SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
+ SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
+
+ typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator;
+ InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
+ InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
+
+ typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator;
+ RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); }
+ RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }
+
+ int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
+ // ---
+};
+static_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");
+
+struct Import
+{
+ enum ImportType : unsigned int {
+ ImportLibrary = 0x1,
+ ImportFile = 0x2,
+ ImportScript = 0x3,
+ ImportInlineComponent = 0x4
+ };
+ quint32_le type;
+
+ quint32_le uriIndex;
+ quint32_le qualifierIndex;
+
+ Location location;
+ QTypeRevision version;
+ quint16_le reserved;
+
+ Import()
+ {
+ type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0;
+ }
+};
+static_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");
+
+struct QmlUnit
+{
+ quint32_le nImports;
+ quint32_le offsetToImports;
+ quint32_le nObjects;
+ quint32_le offsetToObjects;
+
+ const Import *importAt(int idx) const {
+ return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
+ }
+
+ const Object *objectAt(int idx) const {
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
+ }
+};
+static_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");
+
+enum { QmlCompileHashSpace = 48 };
+static const char magic_str[] = "qv4cdata";
+
+struct Unit
+{
+ // DO NOT CHANGE THESE FIELDS EVER
+ char magic[8];
+ quint32_le version;
+ quint32_le qtVersion;
+ qint64_le sourceTimeStamp;
+ quint32_le unitSize; // Size of the Unit and any depending data.
+ // END DO NOT CHANGE THESE FIELDS EVER
+
+ char libraryVersionHash[QmlCompileHashSpace];
+
+ char md5Checksum[16]; // checksum of all bytes following this field.
+ char dependencyMD5Checksum[16];
+
+ enum : unsigned int {
+ IsJavascript = 0x1,
+ StaticData = 0x2, // Unit data persistent in memory?
+ IsSingleton = 0x4,
+ IsSharedLibrary = 0x8, // .pragma shared?
+ IsESModule = 0x10,
+ PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation
+ IsStrict = 0x40,
+ ListPropertyAssignReplaceIfDefault = 0x80,
+ ListPropertyAssignReplaceIfNotDefault = 0x100,
+ ListPropertyAssignReplace
+ = ListPropertyAssignReplaceIfDefault | ListPropertyAssignReplaceIfNotDefault,
+ ComponentsBound = 0x200,
+ FunctionSignaturesIgnored = 0x400,
+ NativeMethodsAcceptThisObject = 0x800,
+ ValueTypesCopied = 0x1000,
+ ValueTypesAddressable = 0x2000,
+ ValueTypesAssertable = 0x4000,
+ };
+ quint32_le flags;
+ quint32_le stringTableSize;
+ quint32_le offsetToStringTable;
+ quint32_le functionTableSize;
+ quint32_le offsetToFunctionTable;
+ quint32_le classTableSize;
+ quint32_le offsetToClassTable;
+ quint32_le templateObjectTableSize;
+ quint32_le offsetToTemplateObjectTable;
+ quint32_le blockTableSize;
+ quint32_le offsetToBlockTable;
+ quint32_le lookupTableSize;
+ quint32_le offsetToLookupTable;
+ quint32_le regexpTableSize;
+ quint32_le offsetToRegexpTable;
+ quint32_le constantTableSize;
+ quint32_le offsetToConstantTable;
+ quint32_le jsClassTableSize;
+ quint32_le offsetToJSClassTable;
+ quint32_le translationTableSize;
+ quint32_le offsetToTranslationTable;
+ quint32_le localExportEntryTableSize;
+ quint32_le offsetToLocalExportEntryTable;
+ quint32_le indirectExportEntryTableSize;
+ quint32_le offsetToIndirectExportEntryTable;
+ quint32_le starExportEntryTableSize;
+ quint32_le offsetToStarExportEntryTable;
+ quint32_le importEntryTableSize;
+ quint32_le offsetToImportEntryTable;
+ quint32_le moduleRequestTableSize;
+ quint32_le offsetToModuleRequestTable;
+ qint32_le indexOfRootFunction;
+ quint32_le sourceFileIndex;
+ quint32_le finalUrlIndex;
+
+ quint32_le offsetToQmlUnit;
+
+ /* QML specific fields */
+
+ const QmlUnit *qmlUnit() const {
+ return reinterpret_cast<const QmlUnit *>(reinterpret_cast<const char *>(this) + offsetToQmlUnit);
+ }
+
+ QmlUnit *qmlUnit() {
+ return reinterpret_cast<QmlUnit *>(reinterpret_cast<char *>(this) + offsetToQmlUnit);
+ }
+
+ bool isSingleton() const {
+ return flags & Unit::IsSingleton;
+ }
+ /* end QML specific fields*/
+
+ QString stringAtInternal(uint idx) const {
+ Q_ASSERT(idx < stringTableSize);
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
+ const quint32_le offset = offsetTable[idx];
+ const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
+ Q_ASSERT(str->size >= 0);
+ if (str->size == 0)
+ return QString();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
+ if (flags & StaticData)
+ return QString::fromRawData(characters, str->size);
+ return QString(characters, str->size);
+#else
+ const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
+ QString qstr(str->size, Qt::Uninitialized);
+ QChar *ch = qstr.data();
+ for (int i = 0; i < str->size; ++i)
+ ch[i] = QChar(characters[i]);
+ return qstr;
+#endif
+ }
+
+ const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+ const quint32_le *classOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToClassTable); }
+ const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToTemplateObjectTable); }
+ const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
+
+ const Function *functionAt(int idx) const {
+ const quint32_le *offsetTable = functionOffsetTable();
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
+ }
+
+ const Class *classAt(int idx) const {
+ const quint32_le *offsetTable = classOffsetTable();
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Class *>(reinterpret_cast<const char *>(this) + offset);
+ }
+
+ const TemplateObject *templateObjectAt(int idx) const {
+ const quint32_le *offsetTable = templateObjectOffsetTable();
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const TemplateObject *>(reinterpret_cast<const char *>(this) + offset);
+ }
+
+ const Block *blockAt(int idx) const {
+ const quint32_le *offsetTable = blockOffsetTable();
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
+ }
+
+ const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
+ const RegExp *regexpAt(int index) const {
+ return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
+ }
+ const quint64_le *constants() const {
+ return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
+ }
+
+ const JSClassMember *jsClassAt(int idx, int *nMembers) const {
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
+ const quint32_le offset = offsetTable[idx];
+ const char *ptr = reinterpret_cast<const char *>(this) + offset;
+ const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
+ *nMembers = klass->nMembers;
+ return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
+ }
+
+ const TranslationData *translations() const {
+ return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
+ }
+
+ const quint32_le *translationContextIndex() const{
+ if ( translationTableSize == 0)
+ return nullptr;
+ return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this))
+ + offsetToTranslationTable
+ + translationTableSize * sizeof(CompiledData::TranslationData)); }
+
+ quint32_le *translationContextIndex() {
+ if ( translationTableSize == 0)
+ return nullptr;
+ return reinterpret_cast<quint32_le*>((reinterpret_cast<char *>(this))
+ + offsetToTranslationTable
+ + translationTableSize * sizeof(CompiledData::TranslationData)); }
+
+ const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
+ const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
+ const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
+ const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
+
+ const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
+
+ bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
+};
+
+static_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");
+
+struct TypeReference
+{
+ TypeReference(const Location &loc)
+ : location(loc)
+ , needsCreation(false)
+ , errorWhenNotFound(false)
+ {}
+ Location location; // first use
+ bool needsCreation : 1; // whether the type needs to be creatable or not
+ bool errorWhenNotFound: 1;
+};
+
+// Map from name index to location of first use.
+struct TypeReferenceMap : QHash<int, TypeReference>
+{
+ TypeReference &add(int nameIndex, const Location &loc) {
+ Iterator it = find(nameIndex);
+ if (it != end())
+ return *it;
+ return *insert(nameIndex, loc);
+ }
+
+ template <typename CompiledObject>
+ void collectFromObject(const CompiledObject *obj)
+ {
+ if (obj->inheritedTypeNameIndex != 0) {
+ TypeReference &r = this->add(obj->inheritedTypeNameIndex, obj->location);
+ r.needsCreation = true;
+ r.errorWhenNotFound = true;
+ }
+
+ auto prop = obj->propertiesBegin();
+ auto const propEnd = obj->propertiesEnd();
+ for ( ; prop != propEnd; ++prop) {
+ if (!prop->isCommonType()) {
+ TypeReference &r = this->add(prop->commonTypeOrTypeNameIndex(), prop->location);
+ r.errorWhenNotFound = true;
+ }
+ }
+
+ auto binding = obj->bindingsBegin();
+ auto const bindingEnd = obj->bindingsEnd();
+ for ( ; binding != bindingEnd; ++binding) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty)
+ this->add(binding->propertyNameIndex, binding->location);
+ }
+
+ auto ic = obj->inlineComponentsBegin();
+ auto const icEnd = obj->inlineComponentsEnd();
+ for (; ic != icEnd; ++ic) {
+ this->add(ic->nameIndex, ic->location);
+ }
+ }
+
+ template <typename Iterator>
+ void collectFromObjects(Iterator it, Iterator end)
+ {
+ for (; it != end; ++it)
+ collectFromObject(*it);
+ }
+};
+
+using DependentTypesHasher = std::function<QByteArray()>;
+
+struct InlineComponentData {
+
+ InlineComponentData() = default;
+ InlineComponentData(
+ const QQmlType &qmlType, int objectIndex, int nameIndex, int totalObjectCount,
+ int totalBindingCount, int totalParserStatusCount)
+ : qmlType(qmlType)
+ , objectIndex(objectIndex)
+ , nameIndex(nameIndex)
+ , totalObjectCount(totalObjectCount)
+ , totalBindingCount(totalBindingCount)
+ , totalParserStatusCount(totalParserStatusCount)
+ {}
+
+ QQmlType qmlType;
+ int objectIndex = -1;
+ int nameIndex = -1;
+ int totalObjectCount = 0;
+ int totalBindingCount = 0;
+ int totalParserStatusCount = 0;
+};
+
+struct CompilationUnit final : public QQmlRefCounted<CompilationUnit>
+{
+ Q_DISABLE_COPY_MOVE(CompilationUnit)
+
+ const Unit *data = nullptr;
+ const QmlUnit *qmlData = nullptr;
+ QStringList dynamicStrings;
+ const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions = nullptr;
+
+ // pointers either to data->constants() or little-endian memory copy.
+ const StaticValue *constants = nullptr;
+
+ std::unique_ptr<CompilationUnitMapper> backingFile;
+
+ int m_totalBindingsCount = 0; // Number of bindings used in this type
+ int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
+ int m_totalObjectCount = 0; // Number of objects explicitly instantiated
+
+ std::unique_ptr<QString> icRootName;
+ QHash<QString, InlineComponentData> inlineComponentData;
+
+ // index is object index. This allows fast access to the
+ // property data when initializing bindings, avoiding expensive
+ // lookups by string (property name).
+ QVector<BindingPropertyData> bindingPropertyDataPerObject;
+
+ ResolvedTypeReferenceMap resolvedTypes;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+
+ QQmlPropertyCacheVector propertyCaches;
+
+ QQmlType qmlType;
+
+ QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
+
+public:
+ // --- interface for QQmlPropertyCacheCreator
+ using CompiledObject = const CompiledData::Object;
+ using CompiledFunction = const CompiledData::Function;
+ using CompiledBinding = const CompiledData::Binding;
+
+ // Empty dummy. We don't need to do this when loading from cache.
+ class IdToObjectMap
+ {
+ public:
+ void insert(int, int) {}
+ void clear() {}
+
+ // We have already checked uniqueness of IDs when creating the CU
+ bool contains(int) { return false; }
+ };
+
+ explicit CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions,
+ const QString &fileName = QString(), const QString &finalUrlString = QString())
+ : CompilationUnit(unitData, fileName, finalUrlString)
+ {
+ this->aotCompiledFunctions = aotCompiledFunctions;
+ }
+
+ Q_QML_EXPORT CompilationUnit(
+ const Unit *unitData = nullptr, const QString &fileName = QString(),
+ const QString &finalUrlString = QString());
+
+ Q_QML_EXPORT ~CompilationUnit();
+
+ const Unit *unitData() const { return data; }
+
+ void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
+ const QString &fileName = QString(), const QString &finalUrlString = QString())
+ {
+ data = unitData;
+ qmlData = nullptr;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+#endif
+ constants = nullptr;
+ m_fileName.clear();
+ m_finalUrlString.clear();
+ if (!data)
+ return;
+
+ qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
+ const quint64_le *littleEndianConstants = data->constants();
+ for (uint i = 0; i < data->constantTableSize; ++i)
+ bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
+ constants = bigEndianConstants;
+#else
+ constants = reinterpret_cast<const StaticValue*>(data->constants());
+#endif
+
+ m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
+ m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
+ }
+
+ QString stringAt(uint index) const
+ {
+ if (index < data->stringTableSize)
+ return data->stringAtInternal(index);
+
+ const qsizetype dynamicIndex = index - data->stringTableSize;
+ Q_ASSERT(dynamicIndex < dynamicStrings.size());
+ return dynamicStrings.at(dynamicIndex);
+ }
+
+ QString fileName() const { return m_fileName; }
+ QString finalUrlString() const { return m_finalUrlString; }
+
+ QString bindingValueAsString(const CompiledData::Binding *binding) const
+ {
+ using namespace CompiledData;
+ switch (binding->type()) {
+ case Binding::Type_Script:
+ case Binding::Type_String:
+ return stringAt(binding->stringIndex);
+ case Binding::Type_Null:
+ return QStringLiteral("null");
+ case Binding::Type_Boolean:
+ return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
+ case Binding::Type_Number:
+ return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
+ case Binding::Type_Invalid:
+ return QString();
+ case Binding::Type_TranslationById:
+ case Binding::Type_Translation:
+ return stringAt(data->translations()[binding->value.translationDataIndex].stringIndex);
+ default:
+ break;
+ }
+ return QString();
+ }
+
+ QString bindingValueAsScriptString(const CompiledData::Binding *binding) const
+ {
+ return (binding->type() == CompiledData::Binding::Type_String)
+ ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
+ : bindingValueAsString(binding);
+ }
+
+ double bindingValueAsNumber(const CompiledData::Binding *binding) const
+ {
+ if (binding->type() != CompiledData::Binding::Type_Number)
+ return 0.0;
+ return constants[binding->value.constantValueIndex].doubleValue();
+ }
+
+ Q_QML_EXPORT static QString localCacheFilePath(const QUrl &url);
+ Q_QML_EXPORT bool loadFromDisk(
+ const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
+ Q_QML_EXPORT bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+
+ int importCount() const { return qmlData->nImports; }
+ const CompiledData::Import *importAt(int index) const { return qmlData->importAt(index); }
+
+ Q_QML_EXPORT QStringList moduleRequests() const;
+
+ // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
+ // warnings about that code. They include any potential URL interceptions and thus represent the
+ // "physical" location of the code.
+ //
+ // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
+ // They are _not_ intercepted and thus represent the "logical" name for the code.
+
+ QUrl url() const
+ {
+ if (!m_url.isValid())
+ m_url = QUrl(fileName());
+ return m_url;
+ }
+
+ QUrl finalUrl() const
+ {
+ if (!m_finalUrl.isValid())
+ m_finalUrl = QUrl(finalUrlString());
+ return m_finalUrl;
+ }
+
+ ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
+ ResolvedTypeReference *resolvedType(QMetaType type) const;
+
+ QQmlPropertyCache::ConstPtr rootPropertyCache() const
+ {
+ return propertyCaches.at(/*root object*/0);
+ }
+
+ int objectCount() const { return qmlData->nObjects; }
+ const CompiledObject *objectAt(int index) const { return qmlData->objectAt(index); }
+
+ int totalBindingsCount() const;
+ int totalParserStatusCount() const;
+ int totalObjectCount() const;
+
+ int inlineComponentId(const QString &inlineComponentName) const
+ {
+ for (uint i = 0; i < qmlData->nObjects; ++i) {
+ auto *object = qmlData->objectAt(i);
+ for (auto it = object->inlineComponentsBegin(), end = object->inlineComponentsEnd();
+ it != end; ++it) {
+ if (stringAt(it->nameIndex) == inlineComponentName)
+ return it->objectIndex;
+ }
+ }
+ return -1;
+ }
+
+ void finalizeCompositeType(const QQmlType &type);
+
+ bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
+
+ enum class ListPropertyAssignBehavior { Append, Replace, ReplaceIfNotDefault };
+ ListPropertyAssignBehavior listPropertyAssignBehavior() const
+ {
+ if (unitData()->flags & CompiledData::Unit::ListPropertyAssignReplace)
+ return ListPropertyAssignBehavior::Replace;
+ if (unitData()->flags & CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault)
+ return ListPropertyAssignBehavior::ReplaceIfNotDefault;
+ return ListPropertyAssignBehavior::Append;
+ }
+
+ bool ignoresFunctionSignature() const
+ {
+ return unitData()->flags & CompiledData::Unit::FunctionSignaturesIgnored;
+ }
+
+ bool nativeMethodsAcceptThisObjects() const
+ {
+ return unitData()->flags & CompiledData::Unit::NativeMethodsAcceptThisObject;
+ }
+
+ bool valueTypesAreCopied() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesCopied;
+ }
+
+ bool valueTypesAreAddressable() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesAddressable;
+ }
+
+ bool valueTypesAreAssertable() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesAssertable;
+ }
+
+ bool componentsAreBound() const
+ {
+ return unitData()->flags & CompiledData::Unit::ComponentsBound;
+ }
+
+ bool isESModule() const
+ {
+ return unitData()->flags & CompiledData::Unit::IsESModule;
+ }
+
+ bool isSharedLibrary() const
+ {
+ return unitData()->flags & CompiledData::Unit::IsSharedLibrary;
+ }
+
+ struct FunctionIterator
+ {
+ FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
+ : unit(unit), object(object), index(index) {}
+ const CompiledData::Unit *unit;
+ const CompiledObject *object;
+ int index;
+
+ const CompiledFunction *operator->() const
+ {
+ return unit->functionAt(object->functionOffsetTable()[index]);
+ }
+
+ void operator++() { ++index; }
+ bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
+ };
+
+ FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
+ {
+ return FunctionIterator(unitData(), object, 0);
+ }
+
+ FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
+ {
+ return FunctionIterator(unitData(), object, object->nFunctions);
+ }
+
+ QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
+ QMetaType metaType() const { return qmlType.typeId(); }
+
+private:
+ QString m_fileName; // initialized from data->sourceFileIndex
+ QString m_finalUrlString; // initialized from data->finalUrlIndex
+
+ mutable QQmlNullableValue<QUrl> m_url;
+ mutable QQmlNullableValue<QUrl> m_finalUrl;
+};
+
+class SaveableUnitPointer
+{
+ Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
+public:
+ SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) :
+ unit(unit),
+ temporaryFlags(temporaryFlags)
+ {
+ }
+
+ ~SaveableUnitPointer() = default;
+
+ template<typename Char>
+ bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
+ {
+ const quint32_le oldFlags = mutableFlags();
+ auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
+ mutableFlags() |= temporaryFlags;
+ return writer(data<Char>(), size());
+ }
+
+ static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
+ QString *errorString)
+ {
+#if QT_CONFIG(temporaryfile)
+ QSaveFile cacheFile(outputFileName);
+ if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
+ || cacheFile.write(data, size) != size
+ || !cacheFile.commit()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ errorString->clear();
+ return true;
+#else
+ Q_UNUSED(outputFileName);
+ *errorString = QStringLiteral("features.temporaryfile is disabled.");
+ return false;
+#endif
+ }
+
+private:
+ const Unit *unit;
+ quint32 temporaryFlags;
+
+ quint32_le &mutableFlags() const
+ {
+ return const_cast<Unit *>(unit)->flags;
+ }
+
+ template<typename Char>
+ const Char *data() const
+ {
+ Q_STATIC_ASSERT(sizeof(Char) == 1);
+ const Char *dataPtr;
+ memcpy(&dataPtr, &unit, sizeof(dataPtr));
+ return dataPtr;
+ }
+
+ quint32 size() const
+ {
+ return unit->unitSize;
+ }
+};
+
+
+} // CompiledData namespace
+} // QV4 namespace
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QV4::CompiledData::ParameterType::Flags);
+Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif