| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtQml module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| #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/qstring.h> |
| #include <QtCore/qscopeguard.h> |
| #include <QtCore/qvector.h> |
| #include <QtCore/qstringlist.h> |
| #include <QtCore/qhash.h> |
| |
| #if QT_CONFIG(temporaryfile) |
| #include <QtCore/qsavefile.h> |
| #endif |
| |
| #include <private/qendian_p.h> |
| #include <private/qv4staticvalue_p.h> |
| #include <functional> |
| |
| 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 0x25 // Extend size of "register" count (nRegisters) |
| |
| class QIODevice; |
| class QQmlTypeNameCache; |
| class QQmlType; |
| class QQmlEngine; |
| |
| namespace QmlIR { |
| struct Document; |
| } |
| |
| namespace QV4 { |
| namespace Heap { |
| struct Module; |
| struct String; |
| struct InternalClass; |
| }; |
| |
| struct Function; |
| class EvalISelFactory; |
| |
| namespace CompiledData { |
| |
| 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); } |
| 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 |
| { |
| union { |
| quint32 _dummy; |
| quint32_le_bitfield<0, 20> line; |
| quint32_le_bitfield<20, 12> column; |
| }; |
| |
| Location() : _dummy(0) { } |
| |
| inline bool operator<(const Location &other) const { |
| return line < other.line || |
| (line == other.line && column < other.column); |
| } |
| }; |
| 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_Unicode = 0x08, |
| RegExp_Sticky = 0x10 |
| }; |
| union { |
| quint32 _dummy; |
| quint32_le_bitfield<0, 5> flags; |
| quint32_le_bitfield<5, 27> stringIndex; |
| }; |
| |
| RegExp() : _dummy(0) { } |
| }; |
| 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 |
| }; |
| |
| union { |
| quint32 _dummy; |
| quint32_le_bitfield<0, 4> type_and_flags; |
| quint32_le_bitfield<4, 28> nameIndex; |
| }; |
| |
| Lookup() : _dummy(0) { } |
| }; |
| 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 |
| { |
| union { |
| quint32 _dummy; |
| quint32_le_bitfield<0, 31> nameOffset; |
| quint32_le_bitfield<31, 1> isAccessor; |
| }; |
| |
| JSClassMember() : _dummy(0) { } |
| }; |
| 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"); |
| |
| // This data structure is intended to be binary compatible with QStringData/QStaticStringData on |
| // 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped |
| // from a file must be castable to a QStringData regardless of the pointer size. With the first |
| // few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a |
| // ptrdiff_t and thus variable in size. |
| // On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while |
| // on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain |
| // the same value. |
| struct String |
| { |
| qint32_le refcount; // -1 |
| qint32_le size; |
| quint32_le allocAndCapacityReservedFlag; // 0 |
| quint32_le offsetOn32Bit; |
| quint64_le offsetOn64Bit; |
| // uint16 strdata[] |
| |
| static int calculateSize(const QString &str) { |
| return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7; |
| } |
| }; |
| static_assert(sizeof(String) == 24, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
| |
| // Ensure compatibility with QString |
| static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location"); |
| static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location"); |
| static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location"); |
| static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location"); |
| #if QT_POINTER_SIZE == 8 |
| static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location"); |
| #else |
| static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location"); |
| #endif |
| |
| struct CodeOffsetToLine { |
| quint32_le codeOffset; |
| quint32_le line; |
| }; |
| static_assert(sizeof(CodeOffsetToLine) == 8, "CodeOffsetToLine structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
| |
| 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 BuiltinType : unsigned int { |
| Var = 0, Variant, Int, Bool, Real, String, Url, Color, |
| Font, Time, Date, DateTime, Rect, Point, Size, |
| Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin |
| }; |
| |
| struct ParameterType |
| { |
| union { |
| quint32 _dummy; |
| quint32_le_bitfield<0, 1> indexIsBuiltinType; |
| quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; |
| }; |
| }; |
| 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 |
| }; |
| |
| // 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 nLineNumbers; |
| size_t lineNumberOffset() 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 lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); } |
| |
| // 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 CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); } |
| |
| // --- 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 nLines, int nInnerfunctions, int labelInfoSize, int codeSize) { |
| int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32) |
| + nLines*sizeof(CodeOffsetToLine); |
| 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 |
| { |
| quint32_le stringIndex; |
| quint32_le commentIndex; |
| qint32_le number; |
| quint32_le padding; |
| }; |
| 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 ValueType : 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 Flags : unsigned int { |
| IsSignalHandlerExpression = 0x1, |
| IsSignalHandlerObject = 0x2, |
| IsOnAssignment = 0x4, |
| InitializerForReadOnlyDeclaration = 0x8, |
| IsResolvedEnum = 0x10, |
| IsListItem = 0x20, |
| IsBindingToAlias = 0x40, |
| IsDeferredBinding = 0x80, |
| IsCustomParserBinding = 0x100, |
| IsFunctionExpression = 0x200 |
| }; |
| |
| union { |
| quint32_le_bitfield<0, 16> flags; |
| quint32_le_bitfield<16, 16> type; |
| }; |
| 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 isValueBinding() const |
| { |
| if (type == Type_AttachedProperty |
| || type == Type_GroupProperty) |
| return false; |
| if (flags & IsSignalHandlerExpression |
| || flags & IsSignalHandlerObject) |
| return false; |
| return true; |
| } |
| |
| bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); } |
| bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); } |
| |
| bool isSignalHandler() const |
| { |
| if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) { |
| 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 (flags & IsFunctionExpression); } |
| |
| //reverse of Lexer::singleEscape() |
| static QString escapedString(const QString &string) |
| { |
| QString tmp = QLatin1String("\""); |
| for (int i = 0; i < string.length(); ++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 { return type == Type_Translation || type == Type_TranslationById; } |
| bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } |
| |
| 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 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 |
| { |
| quint32_le nameIndex; |
| union { |
| quint32_le_bitfield<0, 29> builtinTypeOrTypeNameIndex; |
| quint32_le_bitfield<29, 1> isBuiltinType; |
| quint32_le_bitfield<30, 1> isList; |
| quint32_le_bitfield<31, 1> isReadOnly; |
| }; |
| |
| Location location; |
| |
| void setBuiltinType(BuiltinType t) |
| { |
| builtinTypeOrTypeNameIndex = static_cast<quint32>(t); |
| isBuiltinType = true; |
| } |
| BuiltinType builtinType() const { |
| if (isBuiltinType) |
| return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex)); |
| return BuiltinType::InvalidBuiltin; |
| } |
| void setCustomType(int nameIndex) |
| { |
| builtinTypeOrTypeNameIndex = nameIndex; |
| isBuiltinType = false; |
| } |
| }; |
| 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 Alias { |
| enum Flags : unsigned int { |
| IsReadOnly = 0x1, |
| Resolved = 0x2, |
| AliasPointsToPointerObject = 0x4 |
| }; |
| union { |
| quint32_le_bitfield<0, 29> nameIndex; |
| quint32_le_bitfield<29, 3> flags; |
| }; |
| union { |
| quint32_le idIndex; // string index |
| quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues) |
| quint32_le_bitfield<31, 1> aliasToLocalAlias; |
| }; |
| 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 isObjectAlias() const { |
| Q_ASSERT(flags & Resolved); |
| return encodedMetaPropertyIndex == -1; |
| } |
| }; |
| 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 |
| { |
| enum Flags : 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 |
| }; |
| |
| // 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; |
| union { |
| quint32_le_bitfield<0, 15> flags; |
| quint32_le_bitfield<15, 1> defaultPropertyIsAlias; |
| qint32_le_bitfield<16, 16> id; |
| }; |
| 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; |
| // Function[] |
| // Property[] |
| // Signal[] |
| // Binding[] |
| |
| static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent) |
| { |
| return ( sizeof(Object) |
| + nFunctions * sizeof(quint32) |
| + nProperties * sizeof(Property) |
| + nAliases * sizeof(Alias) |
| + nEnums * sizeof(quint32) |
| + nSignals * sizeof(quint32) |
| + nBindings * sizeof(Binding) |
| + nNamedObjectsInComponent * sizeof(int) |
| + 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 quint32_le *namedObjectsInComponentTable() const |
| { |
| return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent); |
| } |
| |
| // --- 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; } |
| |
| 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); } |
| |
| int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; } |
| // --- |
| }; |
| static_assert(sizeof(Object) == 68, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
| |
| struct Import |
| { |
| enum ImportType : unsigned int { |
| ImportLibrary = 0x1, |
| ImportFile = 0x2, |
| ImportScript = 0x3 |
| }; |
| quint32_le type; |
| |
| quint32_le uriIndex; |
| quint32_le qualifierIndex; |
| |
| qint32_le majorVersion; |
| qint32_le minorVersion; |
| |
| Location location; |
| |
| Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; } |
| }; |
| static_assert(sizeof(Import) == 24, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); |
| |
| 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 |
| }; |
| 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(int idx) const { |
| Q_ASSERT(idx < int(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); |
| if (str->size == 0) |
| return QString(); |
| #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
| if (flags & StaticData) { |
| const QStringDataPtr holder = { const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) }; |
| return QString(holder); |
| } |
| const QChar *characters = reinterpret_cast<const QChar *>(str + 1); |
| 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 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); } |
| }; |
| |
| 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 propEnd = obj->propertiesEnd(); |
| for ( ; prop != propEnd; ++prop) { |
| if (!prop->isBuiltinType) { |
| TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location); |
| r.errorWhenNotFound = true; |
| } |
| } |
| |
| auto binding = obj->bindingsBegin(); |
| auto bindingEnd = obj->bindingsEnd(); |
| for ( ; binding != bindingEnd; ++binding) { |
| if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) |
| this->add(binding->propertyNameIndex, binding->location); |
| } |
| } |
| |
| template <typename Iterator> |
| void collectFromObjects(Iterator it, Iterator end) |
| { |
| for (; it != end; ++it) |
| collectFromObject(*it); |
| } |
| }; |
| |
| using DependentTypesHasher = std::function<QByteArray()>; |
| |
| // This is how this hooks into the existing structures: |
| |
| struct CompilationUnitBase |
| { |
| Q_DISABLE_COPY(CompilationUnitBase) |
| |
| CompilationUnitBase() = default; |
| ~CompilationUnitBase() = default; |
| |
| CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); } |
| |
| CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept |
| { |
| if (this != &other) { |
| runtimeStrings = other.runtimeStrings; |
| other.runtimeStrings = nullptr; |
| constants = other.constants; |
| other.constants = nullptr; |
| runtimeRegularExpressions = other.runtimeRegularExpressions; |
| other.runtimeRegularExpressions = nullptr; |
| runtimeClasses = other.runtimeClasses; |
| other.runtimeClasses = nullptr; |
| imports = other.imports; |
| other.imports = nullptr; |
| } |
| return *this; |
| } |
| |
| // pointers either to data->constants() or little-endian memory copy. |
| Heap::String **runtimeStrings = nullptr; // Array |
| const StaticValue* constants = nullptr; |
| QV4::StaticValue *runtimeRegularExpressions = nullptr; |
| Heap::InternalClass **runtimeClasses = nullptr; |
| const StaticValue** imports = nullptr; |
| }; |
| |
| Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value); |
| Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0); |
| Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **)); |
| Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *)); |
| Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *)); |
| Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *)); |
| |
| struct CompilationUnit : public CompilationUnitBase |
| { |
| Q_DISABLE_COPY(CompilationUnit) |
| |
| const Unit *data = nullptr; |
| const QmlUnit *qmlData = nullptr; |
| QStringList dynamicStrings; |
| public: |
| using CompiledObject = CompiledData::Object; |
| |
| CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), |
| const QString &finalUrlString = QString()) |
| { |
| setUnitData(unitData, nullptr, fileName, finalUrlString); |
| } |
| |
| ~CompilationUnit() |
| { |
| if (data) { |
| if (data->qmlUnit() != qmlData) |
| free(const_cast<QmlUnit *>(qmlData)); |
| qmlData = nullptr; |
| |
| if (!(data->flags & QV4::CompiledData::Unit::StaticData)) |
| free(const_cast<Unit *>(data)); |
| } |
| data = nullptr; |
| #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
| delete [] constants; |
| constants = nullptr; |
| #endif |
| |
| delete [] imports; |
| imports = nullptr; |
| } |
| |
| CompilationUnit(CompilationUnit &&other) noexcept |
| { |
| *this = std::move(other); |
| } |
| |
| CompilationUnit &operator=(CompilationUnit &&other) noexcept |
| { |
| if (this != &other) { |
| data = other.data; |
| other.data = nullptr; |
| qmlData = other.qmlData; |
| other.qmlData = nullptr; |
| dynamicStrings = std::move(other.dynamicStrings); |
| other.dynamicStrings.clear(); |
| m_fileName = std::move(other.m_fileName); |
| other.m_fileName.clear(); |
| m_finalUrlString = std::move(other.m_finalUrlString); |
| other.m_finalUrlString.clear(); |
| m_module = other.m_module; |
| other.m_module = nullptr; |
| CompilationUnitBase::operator=(std::move(other)); |
| } |
| return *this; |
| } |
| |
| 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(int index) const |
| { |
| if (uint(index) >= data->stringTableSize) |
| return dynamicStrings.at(index - data->stringTableSize); |
| return data->stringAtInternal(index); |
| } |
| |
| QString fileName() const { return m_fileName; } |
| QString finalUrlString() const { return m_finalUrlString; } |
| |
| Heap::Module *module() const { return m_module; } |
| void setModule(Heap::Module *module) { m_module = module; } |
| |
| private: |
| QString m_fileName; // initialized from data->sourceFileIndex |
| QString m_finalUrlString; // initialized from data->finalUrlIndex |
| |
| Heap::Module *m_module = nullptr; |
| }; |
| |
| 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 |
| { |
| auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; }); |
| 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_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE); |
| |
| QT_END_NAMESPACE |
| |
| #endif |