diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2019-07-10 10:46:05 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-07-11 17:22:52 +0200 |
commit | de0d91abbbcf58a66018a08ca77bb4d63a5efda1 (patch) | |
tree | e960c18118f09b793b54c6767d0ffd4633da7d9d /src/qml/compiler | |
parent | 1948139d4c7c76817e13334e8528b01093afa69d (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/compiler')
-rw-r--r-- | src/qml/compiler/compiler.pri | 8 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 16 | ||||
-rw-r--r-- | src/qml/compiler/qv4alloca_p.h | 108 | ||||
-rw-r--r-- | src/qml/compiler/qv4bytecodegenerator_p.h | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4calldata_p.h | 123 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 1326 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler_p.h | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontrolflow_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerglobal_p.h (renamed from src/qml/compiler/qv4stringtoarrayindex_p.h) | 48 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4staticvalue_p.h | 548 |
16 files changed, 43 insertions, 2165 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index c6ae8c6b69..4d6926d420 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -2,21 +2,17 @@ INCLUDEPATH += $$PWD INCLUDEPATH += $$OUT_PWD HEADERS += \ - $$PWD/qv4alloca_p.h \ $$PWD/qv4bytecodegenerator_p.h \ - $$PWD/qv4compileddata_p.h \ $$PWD/qv4compiler_p.h \ $$PWD/qv4compilercontext_p.h \ $$PWD/qv4compilercontrolflow_p.h \ + $$PWD/qv4compilerglobal_p.h \ $$PWD/qv4compilerscanfunctions_p.h \ $$PWD/qv4codegen_p.h \ $$PWD/qqmlirbuilder_p.h \ $$PWD/qv4instr_moth_p.h \ $$PWD/qv4bytecodehandler_p.h \ - $$PWD/qv4calldata_p.h \ - $$PWD/qv4util_p.h \ - $$PWD/qv4staticvalue_p.h \ - $$PWD/qv4stringtoarrayindex_p.h + $$PWD/qv4util_p.h SOURCES += \ $$PWD/qv4bytecodegenerator.cpp \ diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 82b9050c0b..c366c8e459 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -280,7 +280,7 @@ struct Function Function *next; }; -struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression +struct Q_QMLCOMPILER_PRIVATE_EXPORT CompiledFunctionOrExpression { CompiledFunctionOrExpression() {} @@ -291,7 +291,7 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression CompiledFunctionOrExpression *next = nullptr; }; -struct Q_QML_PRIVATE_EXPORT Object +struct Q_QMLCOMPILER_PRIVATE_EXPORT Object { Q_DECLARE_TR_FUNCTIONS(Object) public: @@ -367,7 +367,7 @@ private: PoolList<Function> *functions; }; -struct Q_QML_PRIVATE_EXPORT Pragma +struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma { enum PragmaType { PragmaSingleton = 0x1 @@ -377,7 +377,7 @@ struct Q_QML_PRIVATE_EXPORT Pragma QV4::CompiledData::Location location; }; -struct Q_QML_PRIVATE_EXPORT Document +struct Q_QMLCOMPILER_PRIVATE_EXPORT Document { Document(bool debugMode); QString code; @@ -395,7 +395,7 @@ struct Q_QML_PRIVATE_EXPORT Document QString stringAt(int index) const { return jsGenerator.stringForIndex(index); } }; -class Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives +class Q_QMLCOMPILER_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives { QmlIR::Document *document; QQmlJS::Engine *engine; @@ -409,7 +409,7 @@ public: void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override; }; -struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor +struct Q_QMLCOMPILER_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor { Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator) public: @@ -513,7 +513,7 @@ public: QV4::Compiler::JSUnitGenerator *jsGenerator; }; -struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator +struct Q_QMLCOMPILER_PRIVATE_EXPORT QmlUnitGenerator { void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher()); @@ -522,7 +522,7 @@ private: char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const; }; -struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen +struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen { JSCodeGen(Document *document, const QSet<QString> &globalNames); diff --git a/src/qml/compiler/qv4alloca_p.h b/src/qml/compiler/qv4alloca_p.h deleted file mode 100644 index 65c3e4d65a..0000000000 --- a/src/qml/compiler/qv4alloca_p.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** 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/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h index acd4aa62ea..8c509dd9f1 100644 --- a/src/qml/compiler/qv4bytecodegenerator_p.h +++ b/src/qml/compiler/qv4bytecodegenerator_p.h @@ -62,6 +62,11 @@ class SourceLocation; } namespace QV4 { + +namespace Compiler { +struct Context; +} + namespace Moth { class BytecodeGenerator { diff --git a/src/qml/compiler/qv4calldata_p.h b/src/qml/compiler/qv4calldata_p.h deleted file mode 100644 index 5a5280cb86..0000000000 --- a/src/qml/compiler/qv4calldata_p.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** 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/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 86617aa428..c43ea64e2e 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -48,7 +48,6 @@ #include <private/qqmljsast_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> -#include <private/qv4stringtoarrayindex_p.h> #include <private/qv4staticvalue_p.h> #include <private/qv4compilercontext_p.h> #include <private/qv4compilercontrolflow_p.h> diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 491ecb2a0d..82a4fc3289 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -50,7 +50,6 @@ // We mean it. // -#include "private/qv4global_p.h" #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljsast_p.h> @@ -79,7 +78,7 @@ struct ControlFlow; struct ControlFlowCatch; struct ControlFlowFinally; -class Q_QML_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor +class Q_QMLCOMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor { protected: using BytecodeGenerator = QV4::Moth::BytecodeGenerator; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h deleted file mode 100644 index 60d0c50599..0000000000 --- a/src/qml/compiler/qv4compileddata_p.h +++ /dev/null @@ -1,1326 +0,0 @@ -/**************************************************************************** -** -** 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> - -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. - QV4::Heap::String **runtimeStrings = nullptr; // Array - const StaticValue* constants = nullptr; - QV4::StaticValue *runtimeRegularExpressions = nullptr; - QV4::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/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 22f393eaec..acc4b02e96 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -38,8 +38,8 @@ ****************************************************************************/ #include <qv4compiler_p.h> -#include <qv4compileddata_p.h> #include <qv4codegen_p.h> +#include <private/qv4compileddata_p.h> #include <private/qv4staticvalue_p.h> #include <private/qv4alloca_p.h> #include <private/qqmljslexer_p.h> diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index f5884f6478..4f3c718175 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -53,9 +53,10 @@ #include <QtCore/qstring.h> #include <QtCore/qhash.h> #include <QtCore/qstringlist.h> -#include <private/qv4global_p.h> +#include <private/qv4compilerglobal_p.h> #include <private/qqmljsastfwd_p.h> #include <private/qv4compileddata_p.h> +#include <private/qv4staticvalue_p.h> QT_BEGIN_NAMESPACE @@ -72,10 +73,12 @@ struct JSClassMember; namespace Compiler { +struct Context; +struct Module; struct Class; struct TemplateObject; -struct Q_QML_PRIVATE_EXPORT StringTableGenerator { +struct Q_QMLCOMPILER_PRIVATE_EXPORT StringTableGenerator { StringTableGenerator(); int registerString(const QString &str); @@ -102,7 +105,7 @@ private: bool frozen = false; }; -struct Q_QML_PRIVATE_EXPORT JSUnitGenerator { +struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator { static void generateUnitChecksum(CompiledData::Unit *unit); struct MemberInfo { diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index 1ae7c8c149..8c124ac409 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -50,7 +50,6 @@ // We mean it. // -#include "private/qv4global_p.h" #include <private/qqmljsast_p.h> #include <private/qv4compileddata_p.h> #include <QtCore/QStringList> @@ -62,8 +61,13 @@ QT_BEGIN_NAMESPACE namespace QV4 { +namespace Moth { +class BytecodeGenerator; +} + namespace Compiler { +class Codegen; struct ControlFlow; enum class ContextType { diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h index 8ae618a6d4..5623473726 100644 --- a/src/qml/compiler/qv4compilercontrolflow_p.h +++ b/src/qml/compiler/qv4compilercontrolflow_p.h @@ -50,7 +50,6 @@ // We mean it. // -#include <private/qv4global_p.h> #include <private/qv4codegen_p.h> #include <private/qqmljsast_p.h> #include <private/qv4bytecodegenerator_p.h> diff --git a/src/qml/compiler/qv4stringtoarrayindex_p.h b/src/qml/compiler/qv4compilerglobal_p.h index 61bd988d1e..3478074827 100644 --- a/src/qml/compiler/qv4stringtoarrayindex_p.h +++ b/src/qml/compiler/qv4compilerglobal_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QV4STRINGTOARRAYINDEX_P_H -#define QV4STRINGTOARRAYINDEX_P_H +#ifndef QV4COMPILERGLOBAL_H +#define QV4COMPILERGLOBAL_H // // W A R N I N G @@ -51,46 +51,24 @@ // We mean it. // -#include <QtCore/private/qnumeric_p.h> -#include <QtCore/qstring.h> -#include <limits> +#include <QtCore/qglobal.h> +#include <QString> + +#include <private/qtqmlcompilerglobal_p.h> 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()); -} +enum class ObjectLiteralArgument { + Value, + Method, + Getter, + Setter +}; } // namespace QV4 QT_END_NAMESPACE -#endif // QV4STRINGTOARRAYINDEX_P_H +#endif // QV4COMPILERGLOBAL_H diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h index 84d3ff5e31..f67db030a2 100644 --- a/src/qml/compiler/qv4compilerscanfunctions_p.h +++ b/src/qml/compiler/qv4compilerscanfunctions_p.h @@ -50,7 +50,7 @@ // We mean it. // -#include "private/qv4global_p.h" +#include <private/qtqmlcompilerglobal_p.h> #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsast_p.h> #include <private/qqmljsengine_p.h> diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index ec81701160..c0dd696b8a 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -50,7 +50,7 @@ // // We mean it. // -#include <private/qv4global_p.h> + #include <private/qv4staticvalue_p.h> #include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper #include <qendian.h> diff --git a/src/qml/compiler/qv4staticvalue_p.h b/src/qml/compiler/qv4staticvalue_p.h deleted file mode 100644 index c6b4bdb158..0000000000 --- a/src/qml/compiler/qv4staticvalue_p.h +++ /dev/null @@ -1,548 +0,0 @@ -/**************************************************************************** -** -** 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 <QtQml/private/qtqmlglobal_p.h> -#include <QtQml/private/qv4global_p.h> -#include <QtCore/private/qnumeric_p.h> - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -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 Q_QML_PRIVATE_EXPORT 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; - - QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; } - QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; } - QML_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; } - QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } - QML_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); } - QML_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; } - QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); } - - QML_NEARLY_ALWAYS_INLINE constexpr int int_32() const - { - return int(value()); - } - QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i) - { - setTagValue(quint32(ValueTypeInternal::Integer), quint32(i)); - } - QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); } - - QML_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 - } - - QML_NEARLY_ALWAYS_INLINE double doubleValue() const { - Q_ASSERT(isDouble()); - double d; - StaticValue v = *this; - v._val ^= NaNEncodeMask; - memcpy(&d, &v._val, 8); - return d; - } - - QML_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; - } - - QML_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 |