aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/common
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-07-10 10:46:05 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-07-11 17:22:52 +0200
commitde0d91abbbcf58a66018a08ca77bb4d63a5efda1 (patch)
treee960c18118f09b793b54c6767d0ffd4633da7d9d /src/qml/common
parent1948139d4c7c76817e13334e8528b01093afa69d (diff)
Split compiler and runtime more clearly
Provide different export macros and different top level headers for each, don't include runtime headers from compiler sources. Change-Id: I7dc3f8c95839a00a871ba045ec65af87123154be Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/common')
-rw-r--r--src/qml/common/common.pri32
-rw-r--r--src/qml/common/qv4alloca_p.h108
-rw-r--r--src/qml/common/qv4calldata_p.h123
-rw-r--r--src/qml/common/qv4compileddata_p.h1327
-rw-r--r--src/qml/common/qv4staticvalue_p.h558
-rw-r--r--src/qml/common/qv4stringtoarrayindex_p.h96
6 files changed, 2243 insertions, 1 deletions
diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri
index 9de4fcae16..bcc3ea0fa0 100644
--- a/src/qml/common/common.pri
+++ b/src/qml/common/common.pri
@@ -1,5 +1,35 @@
+!build_pass {
+ # Create a header containing a hash that describes this library. For a
+ # released version of Qt, we'll use the .tag file that is updated by git
+ # archive with the commit hash. For unreleased versions, we'll ask git
+ # describe. Note that it won't update unless qmake is run again, even if
+ # the commit change also changed something in this library.
+ tagFile = $$PWD/../../.tag
+ tag =
+ exists($$tagFile) {
+ tag = $$cat($$tagFile, singleline)
+ QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
+ }
+ !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
+ QML_COMPILE_HASH = $$tag
+ } else:exists($$PWD/../../.git) {
+ commit = $$system(git rev-parse HEAD)
+ QML_COMPILE_HASH = $$commit
+ }
+ compile_hash_contents = \
+ "// Generated file, DO NOT EDIT" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
+ write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
+}
+
HEADERS += \
$$PWD/qqmlapiversion_p.h \
$$PWD/qqmljsdiagnosticmessage_p.h \
$$PWD/qqmljsfixedpoolarray_p.h \
- $$PWD/qqmljsmemorypool_p.h
+ $$PWD/qqmljsmemorypool_p.h \
+ $$PWD/qv4alloca_p.h \
+ $$PWD/qv4calldata_p.h \
+ $$PWD/qv4compileddata_p.h \
+ $$PWD/qv4staticvalue_p.h \
+ $$PWD/qv4stringtoarrayindex_p.h
diff --git a/src/qml/common/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
new file mode 100644
index 0000000000..65c3e4d65a
--- /dev/null
+++ b/src/qml/common/qv4alloca_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 QV4_ALLOCA_H
+#define QV4_ALLOCA_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 <QtCore/private/qglobal_p.h>
+
+#if QT_CONFIG(alloca_h)
+# include <alloca.h>
+#elif QT_CONFIG(alloca_malloc_h)
+# include <malloc.h>
+// This does not matter unless compiling in strict standard mode.
+# ifdef Q_CC_MSVC
+# define alloca _alloca
+# endif
+#else
+# include <stdlib.h>
+#endif
+
+// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
+// the occurrences of alloca() in case it's not supported.
+// Q_ALLOCA_DECLARE and Q_ALLOCA_ASSIGN macros separate
+// memory allocation from the declaration and RAII.
+#define Q_ALLOCA_VAR(type, name, size) \
+ Q_ALLOCA_DECLARE(type, name); \
+ Q_ALLOCA_ASSIGN(type, name, size)
+
+#if QT_CONFIG(alloca)
+
+#define Q_ALLOCA_DECLARE(type, name) \
+ type *name = 0
+
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ name = static_cast<type*>(alloca(size))
+
+#else
+QT_BEGIN_NAMESPACE
+class Qt_AllocaWrapper
+{
+public:
+ Qt_AllocaWrapper() { m_data = 0; }
+ ~Qt_AllocaWrapper() { free(m_data); }
+ void *data() { return m_data; }
+ void allocate(int size) { m_data = malloc(size); memset(m_data, 0, size); }
+private:
+ void *m_data;
+};
+QT_END_NAMESPACE
+
+#define Q_ALLOCA_DECLARE(type, name) \
+ Qt_AllocaWrapper _qt_alloca_##name; \
+ type *name = nullptr
+
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ _qt_alloca_##name.allocate(size); \
+ name = static_cast<type*>(_qt_alloca_##name.data())
+
+#endif
+
+#endif
diff --git a/src/qml/common/qv4calldata_p.h b/src/qml/common/qv4calldata_p.h
new file mode 100644
index 0000000000..5a5280cb86
--- /dev/null
+++ b/src/qml/common/qv4calldata_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QV4CALLDATA_P_H
+#define QV4CALLDATA_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 <private/qv4staticvalue_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct CallData
+{
+ enum Offsets {
+ Function = 0,
+ Context = 1,
+ Accumulator = 2,
+ This = 3,
+ NewTarget = 4,
+ Argc = 5,
+
+ LastOffset = Argc,
+ OffsetCount = LastOffset + 1
+ };
+
+ StaticValue function;
+ StaticValue context;
+ StaticValue accumulator;
+ StaticValue thisObject;
+ StaticValue newTarget;
+ StaticValue _argc;
+
+ int argc() const {
+ Q_ASSERT(_argc.isInteger());
+ return _argc.int_32();
+ }
+
+ void setArgc(int argc) {
+ Q_ASSERT(argc >= 0);
+ _argc.setInt_32(argc);
+ }
+
+ inline ReturnedValue argument(int i) const {
+ return i < argc() ? args[i].asReturnedValue()
+ : StaticValue::undefinedValue().asReturnedValue();
+ }
+
+ StaticValue args[1];
+
+ static Q_DECL_CONSTEXPR int HeaderSize()
+ {
+ return offsetof(CallData, args) / sizeof(QV4::StaticValue);
+ }
+
+ template<typename Value>
+ Value *argValues();
+
+ template<typename Value>
+ const Value *argValues() const;
+};
+
+Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
+Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(StaticValue));
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4CALLDATA_P_H
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
new file mode 100644
index 0000000000..c3ddce5884
--- /dev/null
+++ b/src/qml/common/qv4compileddata_p.h
@@ -0,0 +1,1327 @@
+/****************************************************************************
+**
+** 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 0x24 // Collect function parameter types
+
+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
+ quint16_le sizeOfLocalTemporalDeadZone;
+ quint16_le firstTemporalDeadZoneRegister;
+ quint16_le sizeOfRegisterTemporalDeadZone;
+ quint16_le nRegisters;
+ Location location;
+
+ quint32_le nLabelInfos;
+ 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
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
new file mode 100644
index 0000000000..8160bbb748
--- /dev/null
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -0,0 +1,558 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QV4STATICVALUE_P_H
+#define QV4STATICVALUE_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 <QtCore/private/qnumeric_p.h>
+
+#ifdef QT_NO_DEBUG
+#define QV4_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
+#else
+#define QV4_NEARLY_ALWAYS_INLINE inline
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+// ReturnedValue is used to return values from runtime methods
+// the type has to be a primitive type (no struct or union), so that the compiler
+// will return it in a register on all platforms.
+// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
+typedef quint64 ReturnedValue;
+
+struct Double {
+ quint64 d;
+
+ Double(double dbl) {
+ memcpy(&d, &dbl, sizeof(double));
+ }
+
+ int sign() const {
+ return (d >> 63) ? -1 : 1;
+ }
+
+ bool isDenormal() const {
+ return static_cast<int>((d << 1) >> 53) == 0;
+ }
+
+ int exponent() const {
+ return static_cast<int>((d << 1) >> 53) - 1023;
+ }
+
+ quint64 significant() const {
+ quint64 m = (d << 12) >> 12;
+ if (!isDenormal())
+ m |= (static_cast<quint64>(1) << 52);
+ return m;
+ }
+
+ static int toInt32(double d) {
+ int i = static_cast<int>(d);
+ if (i == d)
+ return i;
+ return Double(d).toInt32();
+ }
+
+ int toInt32() {
+ int e = exponent() - 52;
+ if (e < 0) {
+ if (e <= -53)
+ return 0;
+ return sign() * static_cast<int>(significant() >> -e);
+ } else {
+ if (e > 31)
+ return 0;
+ return sign() * (static_cast<int>(significant()) << e);
+ }
+ }
+};
+
+struct StaticValue
+{
+ StaticValue() = default;
+ constexpr StaticValue(quint64 val) : _val(val) {}
+
+ StaticValue &operator=(ReturnedValue v)
+ {
+ _val = v;
+ return *this;
+ }
+
+ template<typename Value>
+ StaticValue &operator=(const Value &);
+
+ template<typename Value>
+ const Value &asValue() const;
+
+ template<typename Value>
+ Value &asValue();
+
+ /*
+ We use 8 bytes for a value and a different variant of NaN boxing. A Double
+ NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
+ signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
+ processor, and are thus free for us to store other data. We keep pointers in there for
+ managed objects, and encode the other types using the free space given to use by the unused
+ bits for NaN values. This also works for pointers on 64 bit systems, as they all currently
+ only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
+ pointers.)
+
+ We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
+ get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
+ managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
+ the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
+ set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
+ used to encode Null/Int/Bool.
+
+ Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
+
+ Specific bit-sequences:
+ 0 = always 0
+ 1 = always 1
+ x = stored value
+ a,b,c,d = specific bit values, see notes
+
+ 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
+ 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
+ ------------------------------------------------------------------------+--------------
+ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
+ 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
+ a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
+ dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
+ 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
+ 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
+ 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
+ 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
+
+ Notes:
+ - a: xor-ed signbit, always 1 for NaN
+ - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value
+ - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0
+ - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++
+ and JS
+ - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0
+ - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1,
+ so: (val >> (64-15)) == 1
+ - Null, Bool, and Int have bit 48 set, indicating integer-convertible
+ - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
+ any non double results in a NaN
+ - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
+ 63) are zero. No need to shift.
+ */
+
+ quint64 _val;
+
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 0; }
+ static inline int tagOffset() { return 4; }
+#else // !Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 4; }
+ static inline int tagOffset() { return 0; }
+#endif
+ static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
+
+ QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
+ {
+ return int(value());
+ }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
+ {
+ setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
+ }
+ QV4_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
+
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
+ {
+ setTagValue(quint32(ValueTypeInternal::Empty), 0);
+ }
+
+ // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
+ // and use negative numbers here
+ enum QuickType {
+ QT_ManagedOrUndefined = 0,
+ QT_ManagedOrUndefined1 = 1,
+ QT_ManagedOrUndefined2 = 2,
+ QT_ManagedOrUndefined3 = 3,
+ QT_Empty = 4,
+ QT_Null = 5,
+ QT_Bool = 6,
+ QT_Int = 7
+ // all other values are doubles
+ };
+
+ enum Type {
+ Undefined_Type = 0,
+ Managed_Type = 1,
+ Empty_Type = 4,
+ Null_Type = 5,
+ Boolean_Type = 6,
+ Integer_Type = 7,
+ Double_Type = 8
+ };
+
+ inline Type type() const {
+ int t = quickType();
+ if (t < QT_Empty)
+ return _val ? Managed_Type : Undefined_Type;
+ if (t > QT_Int)
+ return Double_Type;
+ return static_cast<Type>(t);
+ }
+
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ull;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-15,
+ IsIntegerOrBool_Shift = 64-16,
+ QuickType_Shift = 64 - 17,
+ IsPositiveIntShift = 31
+ };
+
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ enum class ValueTypeInternal_64 {
+ Empty = Immediate_Mask_64 | 0,
+ Null = Immediate_Mask_64 | 0x08000u,
+ Boolean = Immediate_Mask_64 | 0x10000u,
+ Integer = Immediate_Mask_64 | 0x18000u
+ };
+
+ // Used only by 32-bit encoding
+ enum Masks {
+ SilentNaNBit = 0x00040000,
+ NotDouble_Mask = 0x7ffa0000,
+ };
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
+
+ enum class ValueTypeInternal_32 {
+ Empty = Immediate_Mask_32 | 0,
+ Null = Immediate_Mask_32 | 0x08000u,
+ Boolean = Immediate_Mask_32 | 0x10000u,
+ Integer = Immediate_Mask_32 | 0x18000u
+ };
+
+ enum {
+ Managed_Type_Internal = 0
+ };
+
+ using ValueTypeInternal = ValueTypeInternal_64;
+
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
+
+ inline quint64 quickType() const { return (_val >> QuickType_Shift); }
+
+ // used internally in property
+ inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
+ inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
+ inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
+ inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
+ inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
+ inline bool isNumber() const { return quickType() >= QT_Int; }
+
+ inline bool isUndefined() const { return _val == 0; }
+ inline bool isDouble() const { return (_val >> IsDouble_Shift); }
+ inline bool isManaged() const
+ {
+#if QT_POINTER_SIZE == 4
+ return value() && tag() == Managed_Type_Internal;
+#else
+ return _val && ((_val >> IsManagedOrUndefined_Shift) == 0);
+#endif
+ }
+ inline bool isManagedOrUndefined() const
+ {
+#if QT_POINTER_SIZE == 4
+ return tag() == Managed_Type_Internal;
+#else
+ return ((_val >> IsManagedOrUndefined_Shift) == 0);
+#endif
+ }
+
+ inline bool isIntOrBool() const {
+ return (_val >> IsIntegerOrBool_Shift) == 3;
+ }
+
+ inline bool integerCompatible() const {
+ Q_ASSERT(!isEmpty());
+ return (_val >> IsIntegerConvertible_Shift) == 1;
+ }
+
+ static inline bool integerCompatible(StaticValue a, StaticValue b) {
+ return a.integerCompatible() && b.integerCompatible();
+ }
+
+ static inline bool bothDouble(StaticValue a, StaticValue b) {
+ return a.isDouble() && b.isDouble();
+ }
+
+ inline bool isNaN() const
+ {
+ return (tag() & 0x7ffc0000 ) == 0x00040000;
+ }
+
+ inline bool isPositiveInt() const {
+#if QT_POINTER_SIZE == 4
+ return isInteger() && int_32() >= 0;
+#else
+ return (_val >> IsPositiveIntShift) == (quint64(ValueTypeInternal::Integer) << 1);
+#endif
+ }
+
+ QV4_NEARLY_ALWAYS_INLINE double doubleValue() const {
+ Q_ASSERT(isDouble());
+ double d;
+ StaticValue v = *this;
+ v._val ^= NaNEncodeMask;
+ memcpy(&d, &v._val, 8);
+ return d;
+ }
+
+ QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
+ if (qt_is_nan(d))
+ d = qt_qnan();
+ memcpy(&_val, &d, 8);
+ _val ^= NaNEncodeMask;
+ Q_ASSERT(isDouble());
+ }
+
+ inline bool isInt32() {
+ if (tag() == quint32(ValueTypeInternal::Integer))
+ return true;
+ if (isDouble()) {
+ double d = doubleValue();
+ if (isInt32(d)) {
+ setInt_32(int(d));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ QV4_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
+ int i = int(d);
+ return (i == d && !(d == 0 && std::signbit(d)));
+ }
+
+ double asDouble() const {
+ if (tag() == quint32(ValueTypeInternal::Integer))
+ return int_32();
+ return doubleValue();
+ }
+
+ bool booleanValue() const {
+ return int_32();
+ }
+
+ int integerValue() const {
+ return int_32();
+ }
+
+ inline bool tryIntegerConversion() {
+ bool b = integerCompatible();
+ if (b)
+ setTagValue(quint32(ValueTypeInternal::Integer), value());
+ return b;
+ }
+
+ bool toBoolean() const {
+ if (integerCompatible())
+ return static_cast<bool>(int_32());
+
+ if (isManagedOrUndefined())
+ return false;
+
+ // double
+ const double d = doubleValue();
+ return d && !std::isnan(d);
+ }
+
+ inline int toInt32() const
+ {
+ switch (type()) {
+ case Null_Type:
+ case Boolean_Type:
+ case Integer_Type:
+ return int_32();
+ case Double_Type:
+ return Double::toInt32(doubleValue());
+ case Empty_Type:
+ case Undefined_Type:
+ case Managed_Type:
+ break;
+ }
+ return Double::toInt32(std::numeric_limits<double>::quiet_NaN());
+ }
+
+ ReturnedValue *data_ptr() { return &_val; }
+ constexpr ReturnedValue asReturnedValue() const { return _val; }
+ constexpr static StaticValue fromReturnedValue(ReturnedValue val) { return {val}; }
+
+ inline static constexpr StaticValue emptyValue() { return { tagValue(quint32(ValueTypeInternal::Empty), 0) }; }
+ static inline constexpr StaticValue fromBoolean(bool b) { return { tagValue(quint32(ValueTypeInternal::Boolean), b) }; }
+ static inline constexpr StaticValue fromInt32(int i) { return { tagValue(quint32(ValueTypeInternal::Integer), quint32(i)) }; }
+ inline static constexpr StaticValue undefinedValue() { return { 0 }; }
+ static inline constexpr StaticValue nullValue() { return { tagValue(quint32(ValueTypeInternal::Null), 0) }; }
+
+ static inline StaticValue fromDouble(double d)
+ {
+ StaticValue v;
+ v.setDouble(d);
+ return v;
+ }
+
+ static inline StaticValue fromUInt32(uint i)
+ {
+ StaticValue v;
+ if (i < uint(std::numeric_limits<int>::max())) {
+ v.setTagValue(quint32(ValueTypeInternal::Integer), i);
+ } else {
+ v.setDouble(i);
+ }
+ return v;
+ }
+
+ static double toInteger(double d)
+ {
+ if (std::isnan(d))
+ return +0;
+ if (!d || std::isinf(d))
+ return d;
+ return d >= 0 ? std::floor(d) : std::ceil(d);
+ }
+
+ static int toInt32(double d)
+ {
+ return Double::toInt32(d);
+ }
+
+ static unsigned int toUInt32(double d)
+ {
+ return static_cast<uint>(toInt32(d));
+ }
+};
+Q_STATIC_ASSERT(std::is_trivial<StaticValue>::value);
+
+struct Encode {
+ static constexpr ReturnedValue undefined() {
+ return StaticValue::undefinedValue().asReturnedValue();
+ }
+ static constexpr ReturnedValue null() {
+ return StaticValue::nullValue().asReturnedValue();
+ }
+
+ explicit constexpr Encode(bool b)
+ : val(StaticValue::fromBoolean(b).asReturnedValue())
+ {
+ }
+ explicit Encode(double d) {
+ val = StaticValue::fromDouble(d).asReturnedValue();
+ }
+ explicit constexpr Encode(int i)
+ : val(StaticValue::fromInt32(i).asReturnedValue())
+ {
+ }
+ explicit Encode(uint i) {
+ val = StaticValue::fromUInt32(i).asReturnedValue();
+ }
+ explicit constexpr Encode(ReturnedValue v)
+ : val(v)
+ {
+ }
+ constexpr Encode(StaticValue v)
+ : val(v.asReturnedValue())
+ {
+ }
+
+ template<typename HeapBase>
+ explicit Encode(HeapBase *o);
+
+ explicit Encode(StaticValue *o) {
+ Q_ASSERT(o);
+ val = o->asReturnedValue();
+ }
+
+ static ReturnedValue smallestNumber(double d) {
+ if (StaticValue::isInt32(d))
+ return Encode(static_cast<int>(d));
+ else
+ return Encode(d);
+ }
+
+ constexpr operator ReturnedValue() const {
+ return val;
+ }
+ quint64 val;
+private:
+ explicit Encode(void *);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4STATICVALUE_P_H
diff --git a/src/qml/common/qv4stringtoarrayindex_p.h b/src/qml/common/qv4stringtoarrayindex_p.h
new file mode 100644
index 0000000000..61bd988d1e
--- /dev/null
+++ b/src/qml/common/qv4stringtoarrayindex_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QV4STRINGTOARRAYINDEX_P_H
+#define QV4STRINGTOARRAYINDEX_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 <QtCore/private/qnumeric_p.h>
+#include <QtCore/qstring.h>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+inline uint charToUInt(const QChar *ch) { return ch->unicode(); }
+inline uint charToUInt(const char *ch) { return static_cast<unsigned char>(*ch); }
+
+template <typename T>
+uint stringToArrayIndex(const T *ch, const T *end)
+{
+ uint i = charToUInt(ch) - '0';
+ if (i > 9)
+ return std::numeric_limits<uint>::max();
+ ++ch;
+ // reject "01", "001", ...
+ if (i == 0 && ch != end)
+ return std::numeric_limits<uint>::max();
+
+ while (ch < end) {
+ uint x = charToUInt(ch) - '0';
+ if (x > 9)
+ return std::numeric_limits<uint>::max();
+ if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
+ return std::numeric_limits<uint>::max();
+ ++ch;
+ }
+ return i;
+}
+
+inline uint stringToArrayIndex(const QString &str)
+{
+ return stringToArrayIndex(str.constData(), str.constData() + str.length());
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4STRINGTOARRAYINDEX_P_H