aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-05-20 17:05:50 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-05-31 15:18:55 +0200
commit6c76ee30ce1662ca8f8368de5ebd1e6bcfdf0d9e (patch)
treebea1db48da70a74565afab07801f20f143f8067d /src/qml/compiler
parent2f24150b03a8141b3e64442bcfcc08448b9a79e5 (diff)
Eliminate qmldevtools_build
Move the relevant files into more fitting locations and build the devtools from only parser, compiler and qmldirparser. Change-Id: Ibf37a1187f36d02983f9f43c6622acb243785b7b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/compiler.pri31
-rw-r--r--src/qml/compiler/qqmlirloader.cpp205
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator.cpp101
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h843
-rw-r--r--src/qml/compiler/qqmlpropertyresolver.cpp92
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp729
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator_p.h91
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp1429
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h347
-rw-r--r--src/qml/compiler/qv4alloca_p.h (renamed from src/qml/compiler/qqmlirloader_p.h)71
-rw-r--r--src/qml/compiler/qv4calldata_p.h (renamed from src/qml/compiler/qqmlpropertyresolver_p.h)82
-rw-r--r--src/qml/compiler/qv4compilationunitmapper.cpp62
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp108
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp128
-rw-r--r--src/qml/compiler/qv4compiler.cpp29
-rw-r--r--src/qml/compiler/qv4executablecompilationunit.cpp809
-rw-r--r--src/qml/compiler/qv4executablecompilationunit_p.h324
-rw-r--r--src/qml/compiler/qv4staticvalue_p.h548
-rw-r--r--src/qml/compiler/qv4stringtoarrayindex_p.h (renamed from src/qml/compiler/qv4compilationunitmapper_p.h)55
-rw-r--r--src/qml/compiler/qv4util_p.h195
20 files changed, 908 insertions, 5371 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 3291d6e1f5..c3dd5890d6 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -2,6 +2,7 @@ INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
HEADERS += \
+ $$PWD/qv4alloca_p.h \
$$PWD/qv4bytecodegenerator_p.h \
$$PWD/qv4compileddata_p.h \
$$PWD/qv4compiler_p.h \
@@ -11,7 +12,11 @@ HEADERS += \
$$PWD/qv4codegen_p.h \
$$PWD/qqmlirbuilder_p.h \
$$PWD/qv4instr_moth_p.h \
- $$PWD/qv4bytecodehandler_p.h
+ $$PWD/qv4bytecodehandler_p.h \
+ $$PWD/qv4calldata_p.h \
+ $$PWD/qv4util_p.h \
+ $$PWD/qv4staticvalue_p.h \
+ $$PWD/qv4stringtoarrayindex_p.h
SOURCES += \
$$PWD/qv4bytecodegenerator.cpp \
@@ -24,30 +29,6 @@ SOURCES += \
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4bytecodehandler.cpp
-!qmldevtools_build {
-
-HEADERS += \
- $$PWD/qqmlirloader_p.h \
- $$PWD/qqmlpropertyresolver_p.h \
- $$PWD/qqmltypecompiler_p.h \
- $$PWD/qqmlpropertycachecreator_p.h \
- $$PWD/qqmlpropertyvalidator_p.h \
- $$PWD/qv4compilationunitmapper_p.h \
- $$PWD/qv4executablecompilationunit_p.h
-
-SOURCES += \
- $$PWD/qqmlirloader.cpp \
- $$PWD/qqmlpropertyresolver.cpp \
- $$PWD/qqmltypecompiler.cpp \
- $$PWD/qqmlpropertycachecreator.cpp \
- $$PWD/qqmlpropertyvalidator.cpp \
- $$PWD/qv4compilationunitmapper.cpp \
- $$PWD/qv4executablecompilationunit.cpp
-
-unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
-else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-}
-
gcc {
equals(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -fno-strict-aliasing
}
diff --git a/src/qml/compiler/qqmlirloader.cpp b/src/qml/compiler/qqmlirloader.cpp
deleted file mode 100644
index c2eb6da2fa..0000000000
--- a/src/qml/compiler/qqmlirloader.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmlirloader_p.h"
-#include <private/qqmlirbuilder_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlIRLoader::QQmlIRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
- : unit(qmlData)
- , output(output)
-{
- pool = output->jsParserEngine.pool();
-}
-
-void QQmlIRLoader::load()
-{
- output->jsGenerator.stringTable.initializeFromBackingUnit(unit);
-
- const QV4::CompiledData::QmlUnit *qmlUnit = unit->qmlUnit();
-
- for (quint32 i = 0; i < qmlUnit->nImports; ++i)
- output->imports << qmlUnit->importAt(i);
-
- if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
- QmlIR::Pragma *p = New<QmlIR::Pragma>();
- p->location = QV4::CompiledData::Location();
- p->type = QmlIR::Pragma::PragmaSingleton;
- output->pragmas << p;
- }
-
- for (uint i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
- QmlIR::Object *object = loadObject(serializedObject);
- output->objects.append(object);
- }
-}
-
-struct FakeExpression : public QQmlJS::AST::NullExpression
-{
- FakeExpression(int start, int length)
- : location(start, length)
- {}
-
- virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
- { return location; }
-
- virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
- { return location; }
-
-private:
- QQmlJS::AST::SourceLocation location;
-};
-
-QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
-{
- QmlIR::Object *object = pool->New<QmlIR::Object>();
- object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
-
- object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
- object->location = serializedObject->location;
- object->locationOfIdProperty = serializedObject->locationOfIdProperty;
-
- QVector<int> functionIndices;
- functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
-
- for (uint i = 0; i < serializedObject->nBindings; ++i) {
- QmlIR::Binding *b = pool->New<QmlIR::Binding>();
- *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
- object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
- functionIndices.append(b->value.compiledScriptIndex);
- b->value.compiledScriptIndex = functionIndices.count() - 1;
-
- QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
- foe->nameIndex = 0;
-
- QQmlJS::AST::ExpressionNode *expr;
-
- if (b->stringIndex != quint32(0)) {
- const int start = output->code.length();
- const QString script = output->stringAt(b->stringIndex);
- const int length = script.length();
- output->code.append(script);
- expr = new (pool) FakeExpression(start, length);
- } else
- expr = new (pool) QQmlJS::AST::NullExpression();
- foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
- object->functionsAndExpressions->append(foe);
- }
- }
-
- Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
-
- for (uint i = 0; i < serializedObject->nSignals; ++i) {
- const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
- QmlIR::Signal *s = pool->New<QmlIR::Signal>();
- s->nameIndex = serializedSignal->nameIndex;
- s->location = serializedSignal->location;
- s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
-
- for (uint i = 0; i < serializedSignal->nParameters; ++i) {
- QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
- *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
- s->parameters->append(p);
- }
-
- object->qmlSignals->append(s);
- }
-
- for (uint i = 0; i < serializedObject->nEnums; ++i) {
- const QV4::CompiledData::Enum *serializedEnum = serializedObject->enumAt(i);
- QmlIR::Enum *e = pool->New<QmlIR::Enum>();
- e->nameIndex = serializedEnum->nameIndex;
- e->location = serializedEnum->location;
- e->enumValues = pool->New<QmlIR::PoolList<QmlIR::EnumValue> >();
-
- for (uint i = 0; i < serializedEnum->nEnumValues; ++i) {
- QmlIR::EnumValue *v = pool->New<QmlIR::EnumValue>();
- *static_cast<QV4::CompiledData::EnumValue*>(v) = *serializedEnum->enumValueAt(i);
- e->enumValues->append(v);
- }
-
- object->qmlEnums->append(e);
- }
-
- const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
- for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
- QmlIR::Property *p = pool->New<QmlIR::Property>();
- *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
- object->properties->append(p);
- }
-
- {
- const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable();
- for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) {
- QmlIR::Alias *a = pool->New<QmlIR::Alias>();
- *static_cast<QV4::CompiledData::Alias*>(a) = *serializedAlias;
- object->aliases->append(a);
- }
- }
-
- const quint32_le *functionIdx = serializedObject->functionOffsetTable();
- for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
- QmlIR::Function *f = pool->New<QmlIR::Function>();
- const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
-
- functionIndices.append(*functionIdx);
- f->index = functionIndices.count() - 1;
- f->location = compiledFunction->location;
- f->nameIndex = compiledFunction->nameIndex;
-
- f->formals.allocate(pool, int(compiledFunction->nFormals));
- const quint32_le *formalNameIdx = compiledFunction->formalsTable();
- for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
- f->formals[i] = *formalNameIdx;
-
- object->functions->append(f);
- }
-
- object->runtimeFunctionIndices.allocate(pool, functionIndices);
-
- return object;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp
deleted file mode 100644
index bd4f2a0612..0000000000
--- a/src/qml/compiler/qqmlpropertycachecreator.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmlpropertycachecreator_p.h"
-
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
-
-QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
- : referencingObjectIndex(referencingObjectIndex)
- , instantiatingBinding(instantiatingBinding)
- , instantiatingPropertyName(instantiatingPropertyName)
- , referencingObjectPropertyCache(referencingObjectPropertyCache)
-{
-}
-
-bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
-{
- if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- return true;
-
- Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
- Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
-
- bool notInRevision = false;
- instantiatingProperty = QQmlPropertyResolver(referencingObjectPropertyCache)
- .property(instantiatingPropertyName, &notInRevision,
- QQmlPropertyResolver::IgnoreRevision);
- return instantiatingProperty != nullptr;
-}
-
-QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const
-{
- if (instantiatingProperty) {
- if (instantiatingProperty->isQObject()) {
- return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion());
- } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) {
- return enginePrivate->cache(vtmo, instantiatingProperty->typeMinorVersion());
- }
- }
- return QQmlRefPointer<QQmlPropertyCache>();
-}
-
-void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const
-{
- for (QQmlBindingInstantiationContext pendingBinding: *this) {
- const int groupPropertyObjectIndex = pendingBinding.instantiatingBinding->value.objectIndex;
-
- if (propertyCaches->at(groupPropertyObjectIndex))
- continue;
-
- if (!pendingBinding.resolveInstantiatingProperty())
- continue;
-
- auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate);
- propertyCaches->set(groupPropertyObjectIndex, cache);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
deleted file mode 100644
index 28eea27675..0000000000
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ /dev/null
@@ -1,843 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QQMLPROPERTYCACHECREATOR_P_H
-#define QQMLPROPERTYCACHECREATOR_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/qqmlvaluetype_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlmetaobject_p.h>
-#include <private/qqmlpropertyresolver_p.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QQmlBindingInstantiationContext {
- QQmlBindingInstantiationContext() {}
- QQmlBindingInstantiationContext(int referencingObjectIndex,
- const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName,
- QQmlPropertyCache *referencingObjectPropertyCache);
-
- bool resolveInstantiatingProperty();
- QQmlRefPointer<QQmlPropertyCache> instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const;
-
- int referencingObjectIndex = -1;
- const QV4::CompiledData::Binding *instantiatingBinding = nullptr;
- QString instantiatingPropertyName;
- QQmlRefPointer<QQmlPropertyCache> referencingObjectPropertyCache;
- QQmlPropertyData *instantiatingProperty = nullptr;
-};
-
-struct QQmlPendingGroupPropertyBindings : public QVector<QQmlBindingInstantiationContext>
-{
- void resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const;
-};
-
-struct QQmlPropertyCacheCreatorBase
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
-public:
- static QAtomicInt classIndexCounter;
-};
-
-template <typename ObjectContainer>
-class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase
-{
-public:
- typedef typename ObjectContainer::CompiledObject CompiledObject;
-
- QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
- QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
- QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports);
-
- QQmlCompileError buildMetaObjects();
-
-protected:
- QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
- QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
- QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
-
- QString stringAt(int index) const { return objectContainer->stringAt(index); }
-
- QQmlEnginePrivate * const enginePrivate;
- const ObjectContainer * const objectContainer;
- const QQmlImports * const imports;
- QQmlPropertyCacheVector *propertyCaches;
- QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings;
-};
-
-template <typename ObjectContainer>
-inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
- QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
- QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports)
- : enginePrivate(enginePrivate)
- , objectContainer(objectContainer)
- , imports(imports)
- , propertyCaches(propertyCaches)
- , pendingGroupPropertyBindings(pendingGroupPropertyBindings)
-{
- propertyCaches->resize(objectContainer->objectCount());
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
-{
- QQmlBindingInstantiationContext context;
- return buildMetaObjectRecursively(/*root object*/0, context);
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
-{
- const CompiledObject *obj = objectContainer->objectAt(objectIndex);
-
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0;
- if (!needVMEMetaObject) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
- // If the on assignment is inside a group property, we need to distinguish between QObject based
- // group properties and value type group properties. For the former the base type is derived from
- // the property that references us, for the latter we only need a meta-object on the referencing object
- // because interceptors can't go to the shared value type instances.
- if (context.instantiatingProperty && QQmlValueTypeFactory::isValueType(context.instantiatingProperty->propType())) {
- if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
- const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
- auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
- if (error.isSet())
- return error;
- }
- } else {
- // On assignments are implemented using value interceptors, which require a VME meta object.
- needVMEMetaObject = true;
- }
- break;
- }
- }
- }
-
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
- {
- QQmlCompileError error;
- baseTypeCache = propertyCacheForObject(obj, context, &error);
- if (error.isSet())
- return error;
- }
-
- if (baseTypeCache) {
- if (needVMEMetaObject) {
- QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache);
- if (error.isSet())
- return error;
- } else {
- propertyCaches->set(objectIndex, baseTypeCache);
- }
- }
-
- if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
-
- // Binding to group property where we failed to look up the type of the
- // property? Possibly a group property that is an alias that's not resolved yet.
- // Let's attempt to resolve it after we're done with the aliases and fill in the
- // propertyCaches entry then.
- if (!context.resolveInstantiatingProperty())
- pendingGroupPropertyBindings->append(context);
-
- QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context);
- if (error.isSet())
- return error;
- }
- }
-
- QQmlCompileError noError;
- return noError;
-}
-
-template <typename ObjectContainer>
-inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const
-{
- if (context.instantiatingProperty) {
- return context.instantiatingPropertyCache(enginePrivate);
- } else if (obj->inheritedTypeNameIndex != 0) {
- auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
-
- if (typeRef->isFullyDynamicType) {
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
- return nullptr;
- }
- if (obj->signalCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
- return nullptr;
- }
- if (obj->functionCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
- return nullptr;
- }
- }
-
- return typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- } else if (context.instantiatingBinding && context.instantiatingBinding->isAttachedProperty()) {
- auto *typeRef = objectContainer->resolvedType(
- context.instantiatingBinding->propertyNameIndex);
- Q_ASSERT(typeRef);
- QQmlType qmltype = typeRef->type;
- if (!qmltype.isValid()) {
- QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
- if (imports->resolveType(propertyName, &qmltype, nullptr, nullptr, nullptr)) {
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
-
- const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
- if (!attachedMo) {
- *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
- return nullptr;
- }
- return enginePrivate->cache(attachedMo);
- }
- return nullptr;
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
-{
- QQmlRefPointer<QQmlPropertyCache> cache;
- cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
- obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount()));
-
- propertyCaches->set(objectIndex, cache);
- propertyCaches->setNeedsVMEMetaObject(objectIndex);
-
- struct TypeData {
- QV4::CompiledData::Property::Type dtype;
- int metaType;
- } builtinTypes[] = {
- { QV4::CompiledData::Property::Var, QMetaType::QVariant },
- { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
- { QV4::CompiledData::Property::Int, QMetaType::Int },
- { QV4::CompiledData::Property::Bool, QMetaType::Bool },
- { QV4::CompiledData::Property::Real, QMetaType::Double },
- { QV4::CompiledData::Property::String, QMetaType::QString },
- { QV4::CompiledData::Property::Url, QMetaType::QUrl },
- { QV4::CompiledData::Property::Color, QMetaType::QColor },
- { QV4::CompiledData::Property::Font, QMetaType::QFont },
- { QV4::CompiledData::Property::Time, QMetaType::QTime },
- { QV4::CompiledData::Property::Date, QMetaType::QDate },
- { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
- { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
- { QV4::CompiledData::Property::Point, QMetaType::QPointF },
- { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
- { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
- { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
- { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
- { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
- { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
-};
- static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
-
- QByteArray newClassName;
-
- if (objectIndex == /*root object*/0) {
- const QString path = objectContainer->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
- }
- if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache.data()).className();
- newClassName.append("_QML_");
- newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
- }
-
- cache->_dynamicClassName = newClassName;
-
- int varPropCount = 0;
-
- QQmlPropertyResolver resolver(baseTypeCache);
-
- auto p = obj->propertiesBegin();
- auto pend = obj->propertiesEnd();
- for ( ; p != pend; ++p) {
- if (p->type == QV4::CompiledData::Property::Var)
- varPropCount++;
-
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
- if (d && d->isFinal())
- return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
- }
-
- auto a = obj->aliasesBegin();
- auto aend = obj->aliasesEnd();
- for ( ; a != aend; ++a) {
- bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
- if (d && d->isFinal())
- return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
- }
-
- int effectivePropertyIndex = cache->propertyIndexCacheStart;
- int effectiveMethodIndex = cache->methodIndexCacheStart;
-
- // For property change signal override detection.
- // We prepopulate a set of signal names which already exist in the object,
- // and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache.data();
- while ((parentCache = parentCache->parent())) {
- if (int pSigCount = parentCache->signalCount()) {
- int pSigOffset = parentCache->signalOffset();
- for (int i = pSigOffset; i < pSigCount; ++i) {
- QQmlPropertyData *currPSig = parentCache->signal(i);
- // XXX TODO: find a better way to get signal name from the property data :-/
- for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
- iter != parentCache->stringCache.end(); ++iter) {
- if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
- break;
- }
- }
- }
- }
- }
-
- // Set up notify signals for properties - first normal, then alias
- p = obj->propertiesBegin();
- pend = obj->propertiesEnd();
- for ( ; p != pend; ++p) {
- auto flags = QQmlPropertyData::defaultSignalFlags();
-
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
-
- a = obj->aliasesBegin();
- aend = obj->aliasesEnd();
- for ( ; a != aend; ++a) {
- auto flags = QQmlPropertyData::defaultSignalFlags();
-
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
-
- cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
- }
-
- auto e = obj->enumsBegin();
- auto eend = obj->enumsEnd();
- for ( ; e != eend; ++e) {
- const int enumValueCount = e->enumValueCount();
- QVector<QQmlEnumValue> values;
- values.reserve(enumValueCount);
-
- auto enumValue = e->enumValuesBegin();
- auto end = e->enumValuesEnd();
- for ( ; enumValue != end; ++enumValue)
- values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
-
- cache->appendEnum(stringAt(e->nameIndex), values);
- }
-
- // Dynamic signals
- auto s = obj->signalsBegin();
- auto send = obj->signalsEnd();
- for ( ; s != send; ++s) {
- const int paramCount = s->parameterCount();
-
- QList<QByteArray> names;
- names.reserve(paramCount);
- QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
-
- if (paramCount) {
- paramTypes[0] = paramCount;
-
- int i = 0;
- auto param = s->parametersBegin();
- auto end = s->parametersEnd();
- for ( ; param != end; ++param, ++i) {
- names.append(stringAt(param->nameIndex).toUtf8());
- if (param->type < builtinTypeCount) {
- // built-in type
- paramTypes[i + 1] = builtinTypes[param->type].metaType;
- } else {
- // lazily resolved type
- Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
- const QString customTypeName = stringAt(param->customTypeNameIndex);
- QQmlType qmltype;
- if (!imports->resolveType(customTypeName, &qmltype, nullptr, nullptr, nullptr))
- return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
-
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
-
- paramTypes[i + 1] = compilationUnit->metaTypeId;
- } else {
- paramTypes[i + 1] = qmltype.typeId();
- }
- }
- }
- }
-
- auto flags = QQmlPropertyData::defaultSignalFlags();
- if (paramCount)
- flags.hasArguments = true;
-
- QString signalName = stringAt(s->nameIndex);
- if (seenSignals.contains(signalName))
- return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
- seenSignals.insert(signalName);
-
- cache->appendSignal(signalName, flags, effectiveMethodIndex++,
- paramCount?paramTypes.constData():nullptr, names);
- }
-
-
- // Dynamic slots
- auto function = objectContainer->objectFunctionsBegin(obj);
- auto fend = objectContainer->objectFunctionsEnd(obj);
- for ( ; function != fend; ++function) {
- auto flags = QQmlPropertyData::defaultSlotFlags();
-
- const QString slotName = stringAt(function->nameIndex);
- if (seenSignals.contains(slotName))
- return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
- // Note: we don't append slotName to the seenSignals list, since we don't
- // protect against overriding change signals or methods with properties.
-
- QList<QByteArray> parameterNames;
- auto formal = function->formalsBegin();
- auto end = function->formalsEnd();
- for ( ; formal != end; ++formal) {
- flags.hasArguments = true;
- parameterNames << stringAt(*formal).toUtf8();
- }
-
- cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
- }
-
-
- // Dynamic properties
- int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
- int propertyIdx = 0;
- p = obj->propertiesBegin();
- pend = obj->propertiesEnd();
- for ( ; p != pend; ++p, ++propertyIdx) {
- int propertyType = 0;
- int propertTypeMinorVersion = 0;
- QQmlPropertyData::Flags propertyFlags;
-
- if (p->type == QV4::CompiledData::Property::Var) {
- propertyType = QMetaType::QVariant;
- propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
- } else if (p->type < builtinTypeCount) {
- propertyType = builtinTypes[p->type].metaType;
-
- if (p->type == QV4::CompiledData::Property::Variant)
- propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
- } else {
- Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
- p->type == QV4::CompiledData::Property::Custom);
-
- QQmlType qmltype;
- if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
- return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
- }
-
- Q_ASSERT(qmltype.isValid());
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
-
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = compilationUnit->metaTypeId;
- } else {
- propertyType = compilationUnit->listMetaTypeId;
- }
- } else {
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = qmltype.typeId();
- propertTypeMinorVersion = qmltype.minorVersion();
- } else {
- propertyType = qmltype.qListTypeId();
- }
- }
-
- if (p->type == QV4::CompiledData::Property::Custom)
- propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- else
- propertyFlags.type = QQmlPropertyData::Flags::QListType;
- }
-
- if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
- propertyFlags.isWritable = true;
-
-
- QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
- cache->_defaultPropertyName = propertyName;
- cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, propertTypeMinorVersion, effectiveSignalIndex);
-
- effectiveSignalIndex++;
- }
-
- QQmlCompileError noError;
- return noError;
-}
-
-template <typename ObjectContainer>
-class QQmlPropertyCacheAliasCreator
-{
-public:
- typedef typename ObjectContainer::CompiledObject CompiledObject;
-
- QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
-
- void appendAliasPropertiesToMetaObjects();
-
- QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
-
-private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
- QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags);
-
- void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
-
- int objectForId(const CompiledObject &component, int id) const;
-
- QQmlPropertyCacheVector *propertyCaches;
- const ObjectContainer *objectContainer;
-};
-
-template <typename ObjectContainer>
-inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
- : propertyCaches(propertyCaches)
- , objectContainer(objectContainer)
-{
-
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
-{
- // skip the root object (index 0) as that one does not have a first object index originating
- // from a binding.
- for (int i = 1; i < objectContainer->objectCount(); ++i) {
- const CompiledObject &component = *objectContainer->objectAt(i);
- if (!(component.flags & QV4::CompiledData::Object::IsComponent))
- continue;
-
- const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
- }
-
- const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
-{
- QVector<int> objectsWithAliases;
- collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
- if (objectsWithAliases.isEmpty())
- return;
-
- const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
-
- const int targetObjectIndex = objectForId(component, alias->targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
-
- if (alias->aliasToLocalAlias)
- continue;
-
- if (alias->encodedMetaPropertyIndex == -1)
- continue;
-
- const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
-
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- if (!targetProperty)
- return false;
- }
- return true;
- };
-
- do {
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(objectsWithAliases)) {
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
-
- if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
-
- }
- qSwap(objectsWithAliases, pendingObjects);
- } while (!objectsWithAliases.isEmpty());
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (object.aliasCount() > 0)
- objectsWithAliases->append(objectIndex);
-
- // Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return;
-
- auto binding = object.bindingsBegin();
- auto end = object.bindingsEnd();
- for (; binding != end; ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
- }
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
- const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
- QQmlPropertyData::Flags *propertyFlags)
-{
- *type = 0;
- bool writable = false;
- bool resettable = false;
-
- propertyFlags->isAlias = true;
-
- if (alias.aliasToLocalAlias) {
- const QV4::CompiledData::Alias *lastAlias = &alias;
- QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
-
- do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
- const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
- Q_ASSERT(targetObject);
-
- auto nextAlias = targetObject->aliasesBegin();
- for (uint i = 0; i < lastAlias->localAliasIndex; ++i)
- ++nextAlias;
-
- const QV4::CompiledData::Alias *targetAlias = &(*nextAlias);
- if (seenAliases.contains(targetAlias)) {
- return QQmlCompileError(targetAlias->location,
- QQmlPropertyCacheCreatorBase::tr("Cyclic alias"));
- }
-
- seenAliases.append(targetAlias);
- lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
-
- return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags);
- }
-
- const int targetObjectIndex = objectForId(component, alias.targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
- const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
-
- if (alias.encodedMetaPropertyIndex == -1) {
- Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
- auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
- if (!typeRef) {
- // Can be caused by the alias target not being a valid id or property. E.g.:
- // property alias dataValue: dataVal
- // invalidAliasComponent { id: dataVal }
- return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
- }
-
- if (typeRef->type.isValid())
- *type = typeRef->type.typeId();
- else
- *type = typeRef->compilationUnit->metaTypeId;
-
- *minorVersion = typeRef->minorVersion;
-
- propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType;
- } else {
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex();
- int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex();
-
- QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- Q_ASSERT(targetProperty);
-
- *type = targetProperty->propType();
-
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
-
- if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QVariant::Int;
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).userType();
- } else {
- if (targetProperty->isEnum()) {
- *type = QVariant::Int;
- } else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
-
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
- }
- }
- }
-
- propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable;
- propertyFlags->isResettable = resettable;
- return QQmlCompileError();
-}
-
-template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
- const CompiledObject &component, int objectIndex)
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (!object.aliasCount())
- return QQmlCompileError();
-
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- Q_ASSERT(propertyCache);
-
- int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
-
- int aliasIndex = 0;
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias, ++aliasIndex) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
-
- int type = 0;
- int minorVersion = 0;
- QQmlPropertyData::Flags propertyFlags;
- QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags);
- if (error.isSet())
- return error;
-
- const QString propertyName = objectContainer->stringAt(alias->nameIndex);
-
- if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
- propertyCache->_defaultPropertyName = propertyName;
-
- propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, minorVersion, effectiveSignalIndex++);
- }
-
- return QQmlCompileError();
-}
-
-template <typename ObjectContainer>
-inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
-{
- for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
- const int candidateIndex = component.namedObjectsInComponentTable()[i];
- const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.id == id)
- return candidateIndex;
- }
- return -1;
-}
-
-QT_END_NAMESPACE
-
-#endif // QQMLPROPERTYCACHECREATOR_P_H
diff --git a/src/qml/compiler/qqmlpropertyresolver.cpp b/src/qml/compiler/qqmlpropertyresolver.cpp
deleted file mode 100644
index 90eaca0b90..0000000000
--- a/src/qml/compiler/qqmlpropertyresolver.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmlpropertyresolver_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision,
- RevisionCheck check) const
-{
- if (notInRevision) *notInRevision = false;
-
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
-
- // Find the first property
- while (d && d->isFunction())
- d = cache->overrideData(d);
-
- if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) {
- if (notInRevision) *notInRevision = true;
- return nullptr;
- } else {
- return d;
- }
-}
-
-
-QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const
-{
- if (notInRevision) *notInRevision = false;
-
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
- if (notInRevision) *notInRevision = false;
-
- while (d && !(d->isFunction()))
- d = cache->overrideData(d);
-
- if (d && !cache->isAllowedInRevision(d)) {
- if (notInRevision) *notInRevision = true;
- return nullptr;
- } else if (d && d->isSignal()) {
- return d;
- }
-
- if (name.endsWith(QLatin1String("Changed"))) {
- QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
-
- d = property(propName, notInRevision);
- if (d)
- return cache->signal(d->notifyIndex());
- }
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
deleted file mode 100644
index 71d5318652..0000000000
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ /dev/null
@@ -1,729 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmlpropertyvalidator_p.h"
-
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlstringconverters_p.h>
-#include <private/qqmlpropertyresolver_p.h>
-#include <QtCore/qdatetime.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
- : enginePrivate(enginePrivate)
- , compilationUnit(compilationUnit)
- , imports(imports)
- , qmlUnit(compilationUnit->unitData())
- , propertyCaches(compilationUnit->propertyCaches)
- , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
-{
- bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
-}
-
-QVector<QQmlCompileError> QQmlPropertyValidator::validate()
-{
- return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr);
-}
-
-typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
-
-struct BindingFinder
-{
- bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
- {
- return name < binding->propertyNameIndex;
- }
- bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
- {
- return binding->propertyNameIndex < name;
- }
- bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
- {
- return lhs->propertyNameIndex < rhs->propertyNameIndex;
- }
-};
-
-QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
-{
- const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
-
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->nBindings == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return validateObject(componentBinding->value.objectIndex, componentBinding);
- }
-
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
- if (!propertyCache)
- return QVector<QQmlCompileError>();
-
- QQmlCustomParser *customParser = nullptr;
- if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid())
- customParser = typeRef->type.customParser();
- }
-
- QList<const QV4::CompiledData::Binding*> customBindings;
-
- // Collect group properties first for sanity checking
- // vector values are sorted by property name string index.
- GroupPropertyVector groupProperties;
- const QV4::CompiledData::Binding *binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (!binding->isGroupProperty())
- continue;
-
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- continue;
-
- if (populatingValueTypeGroupProperty) {
- return recordError(binding->location, tr("Property assignment expected"));
- }
-
- GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- groupProperties.insert(pos, binding);
- }
-
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
- if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
- defaultPropertyName = cache->defaultPropertyName();
- defaultProperty = cache->defaultProperty();
- } else {
- defaultPropertyName = propertyCache->defaultPropertyName();
- defaultProperty = propertyCache->defaultProperty();
- }
-
- QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
-
- binding = obj->bindingTable();
- for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- QString name = stringAt(binding->propertyNameIndex);
-
- if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- customBindings << binding;
- continue;
- }
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
- && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- customBindings << binding;
- continue;
- }
- }
-
- bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
-
- bool notInRevision = false;
- QQmlPropertyData *pd = nullptr;
- if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
- pd = propertyResolver.signal(name, &notInRevision);
- } else {
- pd = propertyResolver.property(name, &notInRevision,
- QQmlPropertyResolver::CheckRevision);
- }
-
- if (notInRevision) {
- QString typeName = stringAt(obj->inheritedTypeNameIndex);
- auto *objectType = resolvedType(obj->inheritedTypeNameIndex);
- if (objectType && objectType->type.isValid()) {
- return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type.module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
- } else {
- return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
- }
- }
- } else {
- if (isGroupProperty)
- return recordError(binding->location, tr("Cannot assign a value directly to a grouped property"));
-
- pd = defaultProperty;
- name = defaultPropertyName;
- bindingToDefaultProperty = true;
- }
-
- if (pd)
- collectedBindingPropertyData[i] = pd;
-
- if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
- QQmlType type;
- QQmlImportNamespace *typeNamespace = nullptr;
- imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, nullptr, &typeNamespace);
- if (typeNamespace)
- return recordError(binding->location, tr("Invalid use of namespace"));
- return recordError(binding->location, tr("Invalid attached object assignment"));
- }
-
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- const bool populatingValueTypeGroupProperty
- = pd
- && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
- const QVector<QQmlCompileError> subObjectValidatorErrors
- = validateObject(binding->value.objectIndex, binding,
- populatingValueTypeGroupProperty);
- if (!subObjectValidatorErrors.isEmpty())
- return subObjectValidatorErrors;
- }
-
- // Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- return recordError(binding->location, tr("Attached properties cannot be used here"));
- }
- continue;
- }
-
- if (pd) {
- GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
- const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
-
- if (!pd->isWritable()
- && !pd->isQList()
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
- ) {
-
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
- return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
- return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- }
-
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
- QString error;
- if (pd->propType() == qMetaTypeId<QQmlScriptString>())
- error = tr( "Cannot assign multiple values to a script property");
- else
- error = tr( "Cannot assign multiple values to a singular property");
- return recordError(binding->valueLocation, error);
- }
-
- if (!bindingToDefaultProperty
- && !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && assigningToGroupProperty) {
- QV4::CompiledData::Location loc = binding->valueLocation;
- if (loc < (*assignedGroupProperty)->valueLocation)
- loc = (*assignedGroupProperty)->valueLocation;
-
- if (pd && QQmlValueTypeFactory::isValueType(pd->propType()))
- return recordError(loc, tr("Property has already been assigned a value"));
- return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
- }
-
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding);
- if (bindingError.isSet())
- return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- QQmlCompileError bindingError = validateObjectBinding(pd, name, binding);
- if (bindingError.isSet())
- return recordError(bindingError);
- } else if (binding->isGroupProperty()) {
- if (QQmlValueTypeFactory::isValueType(pd->propType())) {
- if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())) {
- if (!pd->isWritable()) {
- return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
- }
- } else {
- return recordError(binding->location, tr("Invalid grouped property access"));
- }
- } else {
- if (!enginePrivate->propertyCacheForType(pd->propType())) {
- return recordError(binding->location,
- tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(pd->propType())))
- );
- }
- }
- }
- } else {
- if (customParser) {
- customBindings << binding;
- continue;
- }
- if (bindingToDefaultProperty) {
- return recordError(binding->location, tr("Cannot assign to non-existent default property"));
- } else {
- return recordError(binding->location, tr("Cannot assign to non-existent property \"%1\"").arg(name));
- }
- }
- }
-
- if (obj->idNameIndex) {
- if (populatingValueTypeGroupProperty)
- return recordError(obj->locationOfIdProperty, tr("Invalid use of id property with a value type"));
-
- bool notInRevision = false;
- collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
- }
-
- if (customParser && !customBindings.isEmpty()) {
- customParser->clearErrors();
- customParser->validator = this;
- customParser->engine = enginePrivate;
- customParser->imports = &imports;
- customParser->verifyBindings(compilationUnit, customBindings);
- customParser->validator = nullptr;
- customParser->engine = nullptr;
- customParser->imports = (QQmlImports*)nullptr;
- QVector<QQmlCompileError> parserErrors = customParser->errors();
- if (!parserErrors.isEmpty())
- return parserErrors;
- }
-
- (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
-
- QVector<QQmlCompileError> noError;
- return noError;
-}
-
-QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
-{
- if (property->isQList()) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
- }
-
- QQmlCompileError noError;
-
- if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
- return noError;
-
- QString value = compilationUnit->bindingValueAsString(binding);
- QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
- bool ok;
- if (p.isFlagType()) {
- p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
- } else
- p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
-
- if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
- }
- return noError;
- }
-
- auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- QQmlError warning;
- warning.setUrl(compilationUnit->url());
- warning.setLine(binding->valueLocation.line);
- warning.setColumn(binding->valueLocation.column);
- warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
- "is deprecated. This will become a compile error in "
- "future versions of Qt."));
- enginePrivate->warning(warning);
- return noError;
- }
- return QQmlCompileError(binding->valueLocation, error);
- };
-
- switch (property->propType()) {
- case QMetaType::QVariant:
- break;
- case QVariant::String: {
- if (!binding->evaluatesToString()) {
- return warnOrError(tr("Invalid property assignment: string expected"));
- }
- }
- break;
- case QVariant::StringList: {
- if (!binding->evaluatesToString()) {
- return warnOrError(tr("Invalid property assignment: string or string list expected"));
- }
- }
- break;
- case QVariant::ByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
- }
- break;
- case QVariant::Url: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return warnOrError(tr("Invalid property assignment: url expected"));
- }
- }
- break;
- case QVariant::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = compilationUnit->bindingValueAsNumber(binding);
- if (double(uint(d)) == d)
- return noError;
- }
- return warnOrError(tr("Invalid property assignment: unsigned int expected"));
- }
- break;
- case QVariant::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = compilationUnit->bindingValueAsNumber(binding);
- if (double(int(d)) == d)
- return noError;
- }
- return warnOrError(tr("Invalid property assignment: int expected"));
- }
- break;
- case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return warnOrError(tr("Invalid property assignment: number expected"));
- }
- }
- break;
- case QVariant::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return warnOrError(tr("Invalid property assignment: number expected"));
- }
- }
- break;
- case QVariant::Color: {
- bool ok = false;
- QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: color expected"));
- }
- }
- break;
-#if QT_CONFIG(datestring)
- case QVariant::Date: {
- bool ok = false;
- QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: date expected"));
- }
- }
- break;
- case QVariant::Time: {
- bool ok = false;
- QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: time expected"));
- }
- }
- break;
- case QVariant::DateTime: {
- bool ok = false;
- QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: datetime expected"));
- }
- }
- break;
-#endif // datestring
- case QVariant::Point: {
- bool ok = false;
- QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: point expected"));
- }
- }
- break;
- case QVariant::PointF: {
- bool ok = false;
- QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: point expected"));
- }
- }
- break;
- case QVariant::Size: {
- bool ok = false;
- QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: size expected"));
- }
- }
- break;
- case QVariant::SizeF: {
- bool ok = false;
- QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: size expected"));
- }
- }
- break;
- case QVariant::Rect: {
- bool ok = false;
- QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: rect expected"));
- }
- }
- break;
- case QVariant::RectF: {
- bool ok = false;
- QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
- if (!ok) {
- return warnOrError(tr("Invalid property assignment: point expected"));
- }
- }
- break;
- case QVariant::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- return warnOrError(tr("Invalid property assignment: boolean expected"));
- }
- }
- break;
- case QVariant::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 2D vector expected"));
- }
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 3D vector expected"));
- }
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 4D vector expected"));
- }
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: quaternion expected"));
- }
- }
- break;
- case QVariant::RegExp:
- case QVariant::RegularExpression:
- return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
- default: {
- // generate single literal value assignment to a list property if required
- if (property->propType() == qMetaTypeId<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
- if (ok) {
- double n = compilationUnit->bindingValueAsNumber(binding);
- if (double(int(n)) != n)
- ok = false;
- }
- if (!ok)
- return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
- break;
- } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
- if (!binding->evaluatesToString()) {
- return warnOrError(tr("Invalid property assignment: string or array of strings expected"));
- }
- break;
- } else if (property->propType() == qMetaTypeId<QJSValue>()) {
- break;
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
- break;
- } else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
- break;
- }
-
- // otherwise, try a custom type assignment
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
- if (!converter) {
- return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
- }
- }
- break;
- }
- return noError;
-}
-
-/*!
- Returns true if from can be assigned to a (QObject) property of type
- to.
-*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
-{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
-
- while (fromMo) {
- if (fromMo == toMo)
- return true;
- fromMo = fromMo->parent();
- }
- return false;
-}
-
-QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
-{
- QVector<QQmlCompileError> errors;
- errors.append(QQmlCompileError(location, description));
- return errors;
-}
-
-QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const
-{
- QVector<QQmlCompileError> errors;
- errors.append(error);
- return errors;
-}
-
-QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
-{
- QQmlCompileError noError;
-
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
-
- bool isValueSource = false;
- bool isPropertyInterceptor = false;
-
- const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
- if (auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
- QQmlRefPointer<QQmlPropertyCache> cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- const QMetaObject *mo = cache->firstCppMetaObject();
- QQmlType qmlType;
- while (mo && !qmlType.isValid()) {
- qmlType = QQmlMetaType::qmlType(mo);
- mo = mo->superClass();
- }
- Q_ASSERT(qmlType.isValid());
-
- isValueSource = qmlType.propertyValueSourceCast() != -1;
- isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
- }
-
- if (!isValueSource && !isPropertyInterceptor) {
- return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
- }
-
- return noError;
- }
-
- if (QQmlMetaType::isInterface(property->propType())) {
- // Can only check at instantiation time if the created sub-object successfully casts to the
- // target interface.
- return noError;
- } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
- // We can convert everything to QVariant :)
- return noError;
- } else if (property->isQList()) {
- const int listType = enginePrivate->listType(property->propType());
- if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
- if (!canCoerce(listType, source)) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
- }
- }
- return noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
- return noError;
- } else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- auto typeName = QMetaType::typeName(property->propType());
- return QQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>"))
- .arg(propertyName));
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
- } else {
- // We want to use the raw metaObject here as the raw metaobject is the
- // actual property type before we applied any extensions that might
- // effect the properties on the type, but don't effect assignability
- // Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
-
- // Will be true if the assigned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
- if (propertyMetaObject) {
- QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
- while (c && !isAssignable) {
- isAssignable |= c == propertyMetaObject;
- c = c->parent();
- }
- }
-
- if (!isAssignable) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
- }
- }
- return noError;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h
deleted file mode 100644
index 8244b2df21..0000000000
--- a/src/qml/compiler/qqmlpropertyvalidator_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QQMLPROPERTYVALIDATOR_P_H
-#define QQMLPROPERTYVALIDATOR_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/qqmltypecompiler_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlPropertyValidator
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
-public:
- QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
-
- QVector<QQmlCompileError> validate();
-
-private:
- QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
- QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
- QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
-
- bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
-
- Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const;
- Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const;
- QString stringAt(int index) const { return compilationUnit->stringAt(index); }
- QV4::ResolvedTypeReference *resolvedType(int id) const
- {
- return compilationUnit->resolvedType(id);
- }
-
- QQmlEnginePrivate *enginePrivate;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
- const QQmlImports &imports;
- const QV4::CompiledData::Unit *qmlUnit;
- const QQmlPropertyCacheVector &propertyCaches;
-
- QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLPROPERTYVALIDATOR_P_H
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
deleted file mode 100644
index 66320b8db9..0000000000
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ /dev/null
@@ -1,1429 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qqmltypecompiler_p.h"
-
-#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlobjectcreator_p.h>
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlcomponent_p.h>
-#include <private/qqmlpropertyresolver_p.h>
-
-#define COMPILE_EXCEPTION(token, desc) \
- { \
- recordError((token)->location, desc); \
- return false; \
- }
-
-QT_BEGIN_NAMESPACE
-
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
- : resolvedTypes(resolvedTypeCache)
- , engine(engine)
- , typeData(typeData)
- , dependencyHasher(dependencyHasher)
- , typeNameCache(typeNameCache)
- , document(parsedQML)
-{
-}
-
-QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
-{
- // Build property caches and VME meta object data
-
- for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
- it != end; ++it) {
- QQmlCustomParser *customParser = (*it)->type.customParser();
- if (customParser)
- customParsers.insert(it.key(), customParser);
- }
-
- QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
-
-
- {
- QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
- engine, this, imports());
- QQmlCompileError error = propertyCacheBuilder.buildMetaObjects();
- if (error.isSet()) {
- recordError(error);
- return nullptr;
- }
- }
-
- {
- QQmlDefaultPropertyMerger merger(this);
- merger.mergeDefaultProperties();
- }
-
- {
- SignalHandlerConverter converter(this);
- if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
- return nullptr;
- }
-
- {
- QQmlEnumTypeResolver enumResolver(this);
- if (!enumResolver.resolveEnumBindings())
- return nullptr;
- }
-
- {
- QQmlCustomParserScriptIndexer cpi(this);
- cpi.annotateBindingsWithScriptStrings();
- }
-
- {
- QQmlAliasAnnotator annotator(this);
- annotator.annotateBindingsToAliases();
- }
-
- // Resolve component boundaries and aliases
-
- {
- // Scan for components, determine their scopes and resolve aliases within the scope.
- QQmlComponentAndAliasResolver resolver(this);
- if (!resolver.resolve())
- return nullptr;
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_propertyCaches);
- }
-
- {
- QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
- if (!deferredAndCustomParserBindingScanner.scanObject())
- return nullptr;
- }
-
- if (!document->javaScriptCompilationUnit.unitData()) {
- // Compile JS binding expressions and signal handlers if necessary
- {
- // We can compile script strings ahead of time, but they must be compiled
- // without type optimizations as their scope is always entirely dynamic.
- QQmlScriptStringScanner sss(this);
- sss.scan();
- }
-
- document->jsModule.fileName = typeData->urlString();
- document->jsModule.finalUrl = typeData->finalUrlString();
- QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
- document->program, &document->jsGenerator.stringTable, engine->v4engine()->illegalNames());
- QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
- if (!jsCodeGen.generateCodeForComponents())
- return nullptr;
-
- document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
- }
-
- // Generate QML compiled type data structures
-
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(*document, dependencyHasher);
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
- = QV4::ExecutableCompilationUnit::create(std::move(
- document->javaScriptCompilationUnit));
- compilationUnit->typeNameCache = typeNameCache;
- compilationUnit->resolvedTypes = *resolvedTypes;
- compilationUnit->propertyCaches = std::move(m_propertyCaches);
- Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
-
- if (errors.isEmpty())
- return compilationUnit;
- else
- return nullptr;
-}
-
-void QQmlTypeCompiler::recordError(QQmlError error)
-{
- error.setUrl(url());
- errors << error;
-}
-
-void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
-{
- QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
- error.setDescription(description);
- error.setUrl(url());
- errors << error;
-}
-
-void QQmlTypeCompiler::recordError(const QQmlCompileError &error)
-{
- recordError(error.location, error.description);
-}
-
-QString QQmlTypeCompiler::stringAt(int idx) const
-{
- return document->stringAt(idx);
-}
-
-int QQmlTypeCompiler::registerString(const QString &str)
-{
- return document->jsGenerator.registerString(str);
-}
-
-int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
-{
- return document->jsGenerator.registerConstant(v);
-}
-
-const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
-{
- return document->javaScriptCompilationUnit.unitData();
-}
-
-const QQmlImports *QQmlTypeCompiler::imports() const
-{
- return &typeData->imports();
-}
-
-QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
-{
- return &document->objects;
-}
-
-void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
-{
- m_propertyCaches = std::move(caches);
- Q_ASSERT(m_propertyCaches.count() > 0);
-}
-
-const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
-{
- return &m_propertyCaches;
-}
-
-QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
-{
- return std::move(m_propertyCaches);
-}
-
-QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
-{
- return document->jsParserEngine.pool();
-}
-
-QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
-{
- return document->jsParserEngine.newStringRef(string);
-}
-
-const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
-{
- return &document->jsGenerator.stringTable;
-}
-
-QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
-{
- return object->bindingAsString(document, scriptIndex);
-}
-
-void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
-{
- const quint32 moduleIdx = registerString(module);
- const quint32 qualifierIdx = registerString(qualifier);
-
- for (int i = 0, count = document->imports.count(); i < count; ++i) {
- const QV4::CompiledData::Import *existingImport = document->imports.at(i);
- if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
- && existingImport->uriIndex == moduleIdx
- && existingImport->qualifierIndex == qualifierIdx)
- return;
- }
- auto pool = memoryPool();
- QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
- import->type = QV4::CompiledData::Import::ImportLibrary;
- import->majorVersion = majorVersion;
- import->minorVersion = minorVersion;
- import->uriIndex = moduleIdx;
- import->qualifierIndex = qualifierIdx;
- document->imports.append(import);
-}
-
-QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
- : compiler(typeCompiler)
-{
-}
-
-
-
-SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , qmlObjects(*typeCompiler->qmlObjects())
- , imports(typeCompiler->imports())
- , customParsers(typeCompiler->customParserCache())
- , illegalNames(typeCompiler->enginePrivate()->v4engine()->illegalNames())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
-{
- for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
- const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
- if (!cache)
- continue;
- if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
- if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
- continue;
- }
- const QString elementName = stringAt(obj->inheritedTypeNameIndex);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
- return false;
- }
- return true;
-}
-
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
-{
- // map from signal name defined in qml itself to list of parameters
- QHash<QString, QStringList> customSignals;
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QString propertyName = stringAt(binding->propertyNameIndex);
- // Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
- auto *typeRef = resolvedType(binding->propertyNameIndex);
- QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (!type.isValid()) {
- if (imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr)) {
- if (type.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
-
- const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
- if (!attachedType)
- COMPILE_EXCEPTION(binding, tr("Non-existent attached object"));
- QQmlPropertyCache *cache = compiler->enginePrivate()->cache(attachedType);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache))
- return false;
- continue;
- }
-
- if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
- continue;
-
- QQmlPropertyResolver resolver(propertyCache);
-
- Q_ASSERT(propertyName.startsWith(QLatin1String("on")));
- propertyName.remove(0, 2);
-
- // Note that the property name could start with any alpha or '_' or '$' character,
- // so we need to do the lower-casing of the first alpha character.
- for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) {
- if (propertyName.at(firstAlphaIndex).isUpper()) {
- propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower();
- break;
- }
- }
-
- QList<QString> parameters;
-
- bool notInRevision = false;
- QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
- if (signal) {
- int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
- sigIndex = propertyCache->originalClone(sigIndex);
-
- bool unnamedParameter = false;
-
- QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
- for (int i = 0; i < parameterNames.count(); ++i) {
- const QString param = QString::fromUtf8(parameterNames.at(i));
- if (param.isEmpty())
- unnamedParameter = true;
- else if (unnamedParameter) {
- COMPILE_EXCEPTION(binding, tr("Signal uses unnamed parameter followed by named parameter."));
- } else if (illegalNames.contains(param)) {
- COMPILE_EXCEPTION(binding, tr("Signal parameter \"%1\" hides global variable.").arg(param));
- }
- parameters += param;
- }
- } else {
- if (notInRevision) {
- // Try assinging it as a property later
- if (resolver.property(propertyName, /*notInRevision ptr*/nullptr))
- continue;
-
- const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
-
- auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
- const QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (type.isValid()) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type.module()).arg(type.majorVersion()).arg(type.minorVersion()));
- } else {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
- }
- }
-
- // Try to look up the signal parameter names in the object itself
-
- // build cache if necessary
- if (customSignals.isEmpty()) {
- for (const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
- const QString &signalName = stringAt(signal->nameIndex);
- customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
- }
-
- for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
- const QString propName = stringAt(property->nameIndex);
- customSignals.insert(propName, QStringList());
- }
- }
-
- QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName);
- if (entry == customSignals.constEnd() && propertyName.endsWith(QLatin1String("Changed"))) {
- QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed")));
- entry = customSignals.constFind(alternateName);
- }
-
- if (entry == customSignals.constEnd()) {
- // Can't find even a custom signal, then just don't do anything and try
- // keeping the binding as a regular property assignment.
- continue;
- }
-
- parameters = entry.value();
- }
-
- // Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
- continue;
- }
-
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
- } else {
- COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
- }
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
-
- QQmlJS::AST::FormalParameterList *paramList = nullptr;
- for (const QString &param : qAsConst(parameters)) {
- QStringRef paramNameRef = compiler->newStringRef(param);
-
- QQmlJS::AST::PatternElement *b = new (pool) QQmlJS::AST::PatternElement(paramNameRef, nullptr);
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b);
- }
-
- if (paramList)
- paramList = paramList->finish(pool);
-
- QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
- QQmlJS::AST::FunctionDeclaration *functionDeclaration = nullptr;
- if (QQmlJS::AST::ExpressionStatement *es = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(foe->node)) {
- if (QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression*>(es->expression)) {
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(fe->name, fe->formals, fe->body);
- functionDeclaration->functionToken = fe->functionToken;
- functionDeclaration->identifierToken = fe->identifierToken;
- functionDeclaration->lparenToken = fe->lparenToken;
- functionDeclaration->rparenToken = fe->rparenToken;
- functionDeclaration->lbraceToken = fe->lbraceToken;
- functionDeclaration->rbraceToken = fe->rbraceToken;
- }
- }
- if (!functionDeclaration) {
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
- QQmlJS::AST::StatementList *body = new (pool) QQmlJS::AST::StatementList(statement);
- body = body->finish();
-
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body);
- functionDeclaration->lbraceToken = functionDeclaration->functionToken
- = foe->node->firstSourceLocation();
- functionDeclaration->rbraceToken = foe->node->lastSourceLocation();
- }
- foe->node = functionDeclaration;
- binding->propertyNameIndex = compiler->registerString(propertyName);
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
- }
- return true;
-}
-
-QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , imports(typeCompiler->imports())
-{
-}
-
-bool QQmlEnumTypeResolver::resolveEnumBindings()
-{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QQmlPropertyResolver resolver(propertyCache);
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
-
- const QString propertyName = stringAt(binding->propertyNameIndex);
- bool notInRevision = false;
- QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
- if (!pd)
- continue;
-
- if (!pd->isEnum() && pd->propType() != QMetaType::Int)
- continue;
-
- if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
- return false;
- }
- }
-
- return true;
-}
-
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject)
-{
- if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
- }
- binding->type = QV4::CompiledData::Binding::Type_Number;
- binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
-// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
- return true;
-}
-
-bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding)
-{
- bool isIntProp = (prop->propType() == QMetaType::Int) && !prop->isEnum();
- if (!prop->isEnum() && !isIntProp)
- return true;
-
- if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
-
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
- const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- if (!string.constData()->isUpper())
- return true;
-
- // we support one or two '.' in the enum phrase:
- // * <TypeName>.<EnumValue>
- // * <TypeName>.<ScopedEnumName>.<EnumValue>
-
- int dot = string.indexOf(QLatin1Char('.'));
- if (dot == -1 || dot == string.length()-1)
- return true;
-
- int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
- if (dot2 != -1 && dot2 != string.length()-1) {
- if (!string.at(dot+1).isUpper())
- return true;
- if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
- return true;
- }
-
- QHashedStringRef typeName(string.constData(), dot);
- const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
- // ### consider supporting scoped enums in Qt namespace
- const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
-
- if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
- // Allow enum assignment to ints.
- bool ok;
- int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
- if (ok) {
- if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
- return false;
- }
- return true;
- }
- QQmlType type;
- imports->resolveType(typeName, &type, nullptr, nullptr, nullptr);
-
- if (!type.isValid() && !isQtObject)
- return true;
-
- int value = 0;
- bool ok = false;
-
- auto *tr = resolvedType(obj->inheritedTypeNameIndex);
- if (type.isValid() && tr && tr->type == type) {
- // When these two match, we can short cut the search
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
- QMetaEnum menum = mprop.enumerator();
- QByteArray enumName = enumValue.toUtf8();
- if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
- return true;
-
- if (mprop.isFlagType()) {
- value = menum.keysToValue(enumName.constData(), &ok);
- } else {
- value = menum.keyToValue(enumName.constData(), &ok);
- }
- } else {
- // Otherwise we have to search the whole type
- if (type.isValid()) {
- if (!scopedEnumName.isEmpty())
- value = type.scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok);
- else
- value = type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
- } else {
- QByteArray enumName = enumValue.toUtf8();
- const QMetaObject *metaObject = StaticQtMetaObject::get();
- for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- value = e.keyToValue(enumName.constData(), &ok);
- }
- }
- }
-
- if (!ok)
- return true;
-
- return assignEnumToBinding(binding, enumValue, value, isQtObject);
-}
-
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
-{
- Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
- *ok = false;
-
- if (scope != QLatin1String("Qt")) {
- QQmlType type;
- imports->resolveType(scope, &type, nullptr, nullptr, nullptr);
- if (!type.isValid())
- return -1;
- if (!enumName.isEmpty())
- return type.scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
- return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
- }
-
- const QMetaObject *mo = StaticQtMetaObject::get();
- int i = mo->enumeratorCount();
- const QByteArray ba = enumValue.toUtf8();
- while (i--) {
- int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
- if (*ok)
- return v;
- }
- return -1;
-}
-
-QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , customParsers(typeCompiler->customParserCache())
-{
-}
-
-void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
-{
- scanObjectRecursively(/*root object*/0);
-}
-
-void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
-{
- const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- if (!annotateScriptBindings)
- annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
- }
-}
-
-QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-}
-
-void QQmlAliasAnnotator::annotateBindingsToAliases()
-{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
-
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (!binding->isValueBinding())
- continue;
- bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
- }
- }
-}
-
-QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-
-}
-
-void QQmlScriptStringScanner::scan()
-{
- const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
- if (!propertyCache)
- continue;
-
- const QmlIR::Object *obj = qmlObjects.at(i);
-
- QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
- if (!pd || pd->propType() != scriptStringMetaType)
- continue;
-
- QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
- }
- }
-}
-
-QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , pool(typeCompiler->memoryPool())
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
-{
-}
-
-static bool isUsableComponent(const QMetaObject *metaObject)
-{
- // The metaObject is a component we're interested in if it either is a QQmlComponent itself
- // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
- // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
-
- if (metaObject == &QQmlComponent::staticMetaObject)
- return true;
-
- for (; metaObject; metaObject = metaObject->superClass()) {
- if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
- return true;
- }
-
- return false;
-}
-
-void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
-{
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- auto *tr = resolvedType(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(tr);
-
- const QMetaObject *firstMetaObject = nullptr;
- if (tr->type.isValid())
- firstMetaObject = tr->type.metaObject();
- else if (tr->compilationUnit)
- firstMetaObject = tr->compilationUnit->rootPropertyCache()->firstCppMetaObject();
- if (isUsableComponent(firstMetaObject))
- continue;
- // if here, not a QQmlComponent, so needs wrapping
-
- QQmlPropertyData *pd = nullptr;
- if (binding->propertyNameIndex != quint32(0)) {
- bool notInRevision = false;
- pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
- } else {
- pd = defaultProperty;
- }
- if (!pd || !pd->isQObject())
- continue;
-
- QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeMinorVersion());
- const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
- while (mo) {
- if (mo == &QQmlComponent::staticMetaObject)
- break;
- mo = mo->superClass();
- }
-
- if (!mo)
- continue;
-
- // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
- QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
- Q_ASSERT(componentType.isValid());
- const QString qualifier = QStringLiteral("QmlInternals");
-
- compiler->addImport(componentType.module(), qualifier, componentType.majorVersion(), componentType.minorVersion());
-
- QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()), compiler->registerString(QString()));
- syntheticComponent->location = binding->valueLocation;
- syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::ResolvedTypeReference;
- typeRef->type = componentType;
- typeRef->majorVersion = componentType.majorVersion();
- typeRef->minorVersion = componentType.minorVersion();
- insertResolvedType(syntheticComponent->inheritedTypeNameIndex, typeRef);
- }
-
- qmlObjects->append(syntheticComponent);
- const int componentIndex = qmlObjects->count() - 1;
- // Keep property caches symmetric
- QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- propertyCaches.append(componentCache);
-
- QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
- *syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
- QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
- Q_ASSERT(error.isEmpty());
- Q_UNUSED(error);
-
- binding->value.objectIndex = componentIndex;
-
- componentRoots.append(componentIndex);
- }
-}
-
-bool QQmlComponentAndAliasResolver::resolve()
-{
- // Detect real Component {} objects as well as implicitly defined components, such as
- // someItemDelegate: Item {}
- // In the implicit case Item is surrounded by a synthetic Component {} because the property
- // on the left hand side is of QQmlComponent type.
- const int objCountWithoutSynthesizedComponents = qmlObjects->count();
- for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- QmlIR::Object *obj = qmlObjects->at(i);
- QQmlPropertyCache *cache = propertyCaches.at(i);
- if (obj->inheritedTypeNameIndex == 0 && !cache)
- continue;
-
- bool isExplicitComponent = false;
-
- if (obj->inheritedTypeNameIndex) {
- auto *tref = resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(tref);
- if (tref->type.metaObject() == &QQmlComponent::staticMetaObject)
- isExplicitComponent = true;
- }
- if (!isExplicitComponent) {
- if (cache)
- findAndRegisterImplicitComponents(obj, cache);
- continue;
- }
-
- obj->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (obj->functionCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
- if (obj->signalCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
-
- if (obj->bindingCount() == 0)
- COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
-
- const QmlIR::Binding *rootBinding = obj->firstBinding();
-
- for (const QmlIR::Binding *b = rootBinding; b; b = b->next) {
- if (b->propertyNameIndex != 0)
- COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
- }
-
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
- COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
-
- // For the root object, we are going to collect ids/aliases and resolve them for as a separate
- // last pass.
- if (i != 0)
- componentRoots.append(i);
-
- }
-
- for (int i = 0; i < componentRoots.count(); ++i) {
- QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
- const QmlIR::Binding *rootBinding = component->firstBinding();
-
- _idToObjectIndex.clear();
-
- _objectsWithAliases.clear();
-
- if (!collectIdsAndAliases(rootBinding->value.objectIndex))
- return false;
-
- component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(componentRoots.at(i)))
- return false;
- }
-
- // Collect ids and aliases for root
- _idToObjectIndex.clear();
- _objectsWithAliases.clear();
-
- collectIdsAndAliases(/*root object*/0);
-
- QmlIR::Object *rootComponent = qmlObjects->at(/*root object*/0);
- rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(/*root object*/0))
- return false;
-
- // Implicit component insertion may have added objects and thus we also need
- // to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(std::move(propertyCaches));
- compiler->setComponentRoots(componentRoots);
-
- return true;
-}
-
-bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
-{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
-
- if (obj->idNameIndex != 0) {
- if (_idToObjectIndex.contains(obj->idNameIndex)) {
- recordError(obj->locationOfIdProperty, tr("id is not unique"));
- return false;
- }
- obj->id = _idToObjectIndex.count();
- _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
- }
-
- if (obj->aliasCount() > 0)
- _objectsWithAliases.append(objectIndex);
-
- // Stop at Component boundary
- if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return true;
-
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
- }
-
- return true;
-}
-
-bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
-{
- if (_objectsWithAliases.isEmpty())
- return true;
-
- QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
-
- bool atLeastOneAliasResolved;
- do {
- atLeastOneAliasResolved = false;
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(_objectsWithAliases)) {
-
- QQmlCompileError error;
- const auto result = resolveAliasesInObject(objectIndex, &error);
-
- if (error.isSet()) {
- recordError(error);
- return false;
- }
-
- if (result == AllAliasesResolved) {
- QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
- if (error.isSet()) {
- recordError(error);
- return false;
- }
- atLeastOneAliasResolved = true;
- } else if (result == SomeAliasesResolved) {
- atLeastOneAliasResolved = true;
- pendingObjects.append(objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
- }
- qSwap(_objectsWithAliases, pendingObjects);
- } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
-
- if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
- const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
- for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
- recordError(alias->location, tr("Circular alias reference detected"));
- return false;
- }
- }
- }
-
- return true;
-}
-
-QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
-{
- const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
- if (!obj->aliasCount())
- return AllAliasesResolved;
-
- int numResolvedAliases = 0;
- bool seenUnresolvedAlias = false;
-
- for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
- continue;
-
- seenUnresolvedAlias = true;
-
- const int idIndex = alias->idIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
- if (targetObjectIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
- break;
- }
-
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
- Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
-
- const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
-
- QStringRef property;
- QStringRef subProperty;
-
- const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
- if (propertySeparator != -1) {
- property = aliasPropertyValue.leftRef(propertySeparator);
- subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
- } else
- property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
-
- QQmlPropertyIndex propIdx;
-
- if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- } else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
- if (!targetCache) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- break;
- }
-
- QQmlPropertyResolver resolver(targetCache);
-
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
-
- // If it's an alias that we haven't resolved yet, try again later.
- if (!targetProperty) {
- bool aliasPointsToOtherAlias = false;
- int localAliasIndex = 0;
- for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
- aliasPointsToOtherAlias = true;
- break;
- }
- }
- if (aliasPointsToOtherAlias) {
- if (targetObjectIndex == objectIndex) {
- alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- ++numResolvedAliases;
- continue;
- }
-
- // restore
- alias->idIndex = idIndex;
- // Try again later and resolve the target alias first.
- break;
- }
- }
-
- if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
- break;
- }
-
- propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
-
- if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
- if (!valueTypeMetaObject) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
-
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
-
- propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
- } else {
- if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
- }
- }
-
- alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
- numResolvedAliases++;
- }
-
- if (numResolvedAliases == 0)
- return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved;
-
- return SomeAliasesResolved;
-}
-
-QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , customParsers(typeCompiler->customParserCache())
- , _seenObjectWithId(false)
-{
-}
-
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
-{
- return scanObject(/*root object*/0);
-}
-
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
-{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
- if (obj->idNameIndex != 0)
- _seenObjectWithId = true;
-
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return scanObject(componentBinding->value.objectIndex);
- }
-
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- if (!propertyCache)
- return true;
-
- QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
- if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
- defaultPropertyName = cache->defaultPropertyName();
- defaultProperty = cache->defaultProperty();
- } else {
- defaultPropertyName = propertyCache->defaultPropertyName();
- defaultProperty = propertyCache->defaultProperty();
- }
-
- QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
-
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QStringList deferredPropertyNames;
- {
- const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
- }
- }
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QQmlPropertyData *pd = nullptr;
- QString name = stringAt(binding->propertyNameIndex);
-
- if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- continue;
- }
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
- && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- continue;
- }
- }
-
- if (name.isEmpty()) {
- pd = defaultProperty;
- name = defaultPropertyName;
- } else {
- if (name.constData()->isUpper())
- continue;
-
- bool notInRevision = false;
- pd = propertyResolver.property(name, &notInRevision,
- QQmlPropertyResolver::CheckRevision);
- }
-
- bool seenSubObjectWithId = false;
-
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- const bool subObjectValid = scanObject(binding->value.objectIndex);
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- if (!subObjectValid)
- return false;
- _seenObjectWithId |= seenSubObjectWithId;
- }
-
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
- && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
-
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
- obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
- }
-
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- if (!pd) {
- if (customParser) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- }
- }
- }
-
- return true;
-}
-
-QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
- : QQmlCompilePass(typeCompiler)
- , customParsers(typeCompiler->customParserCache())
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , v4CodeGen(v4CodeGen)
-{
-}
-
-bool QQmlJSCodeGenerator::generateCodeForComponents()
-{
- const QVector<quint32> &componentRoots = compiler->componentRoots();
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool QQmlJSCodeGenerator::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = qmlObjects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
- return false;
-
- return true;
-}
-
-bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
-{
- QmlIR::Object *object = qmlObjects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
- return true;
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
- if (!jsErrors.isEmpty()) {
- for (const QQmlError &e : jsErrors)
- compiler->recordError(e);
- return false;
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
- }
-
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
-
- return true;
-}
-
-QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
-{
-
-}
-
-void QQmlDefaultPropertyMerger::mergeDefaultProperties()
-{
- for (int i = 0; i < qmlObjects.count(); ++i)
- mergeDefaultProperties(i);
-}
-
-void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
-{
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
- if (!propertyCache)
- return;
-
- QmlIR::Object *object = qmlObjects.at(objectIndex);
-
- QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
- QmlIR::Binding *bindingsToReinsert = nullptr;
- QmlIR::Binding *tail = nullptr;
-
- QmlIR::Binding *previousBinding = nullptr;
- QmlIR::Binding *binding = object->firstBinding();
- while (binding) {
- if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
- previousBinding = binding;
- binding = binding->next;
- continue;
- }
-
- QmlIR::Binding *toReinsert = binding;
- binding = object->unlinkBinding(previousBinding, binding);
-
- if (!tail) {
- bindingsToReinsert = toReinsert;
- tail = toReinsert;
- } else {
- tail->next = toReinsert;
- tail = tail->next;
- }
- tail->next = nullptr;
- }
-
- binding = bindingsToReinsert;
- while (binding) {
- QmlIR::Binding *toReinsert = binding;
- binding = binding->next;
- object->insertSorted(toReinsert);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
deleted file mode 100644
index f588909c42..0000000000
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ /dev/null
@@ -1,347 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QQMLTYPECOMPILER_P_H
-#define QQMLTYPECOMPILER_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 <qglobal.h>
-#include <qqmlerror.h>
-#include <qhash.h>
-#include <private/qqmltypeloader_p.h>
-#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEnginePrivate;
-class QQmlError;
-class QQmlTypeData;
-class QQmlImports;
-
-namespace QmlIR {
-struct Document;
-}
-
-namespace QV4 {
-namespace CompiledData {
-struct QmlUnit;
-struct Location;
-}
-}
-
-struct QQmlTypeCompiler
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
-public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document,
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
-
- // --- interface used by QQmlPropertyCacheCreator
- typedef QmlIR::Object CompiledObject;
- const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
- int objectCount() const { return document->objects.count(); }
- QString stringAt(int idx) const;
- QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
- QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
- QV4::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
- // ---
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compile();
-
- QList<QQmlError> compilationErrors() const { return errors; }
- void recordError(QQmlError error);
- void recordError(const QV4::CompiledData::Location &location, const QString &description);
- void recordError(const QQmlCompileError &error);
-
- int registerString(const QString &str);
- int registerConstant(QV4::ReturnedValue v);
-
- const QV4::CompiledData::Unit *qmlUnit() const;
-
- QUrl url() const { return typeData->finalUrl(); }
- QQmlEnginePrivate *enginePrivate() const { return engine; }
- const QQmlImports *imports() const;
- QVector<QmlIR::Object *> *qmlObjects() const;
- void setPropertyCaches(QQmlPropertyCacheVector &&caches);
- const QQmlPropertyCacheVector *propertyCaches() const;
- QQmlPropertyCacheVector &&takePropertyCaches();
- void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
- const QVector<quint32> &componentRoots() const { return m_componentRoots; }
- QQmlJS::MemoryPool *memoryPool();
- QStringRef newStringRef(const QString &string);
- const QV4::Compiler::StringTableGenerator *stringPool() const;
-
- const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
-
- QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
-
- void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
-
- QV4::ResolvedTypeReference *resolvedType(int id) const
- {
- return resolvedTypes->value(id);
- }
-
-private:
- QList<QQmlError> errors;
- QQmlEnginePrivate *engine;
- QQmlTypeData *typeData;
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher;
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QmlIR::Document *document;
- // index is string index of type name (use obj->inheritedTypeNameIndex)
- QHash<int, QQmlCustomParser*> customParsers;
-
- // index in first hash is component index, vector inside contains object indices of objects with id property
- QVector<quint32> m_componentRoots;
- QQmlPropertyCacheVector m_propertyCaches;
-};
-
-struct QQmlCompilePass
-{
- QQmlCompilePass(QQmlTypeCompiler *typeCompiler);
-
- QString stringAt(int idx) const { return compiler->stringAt(idx); }
-protected:
- void recordError(const QV4::CompiledData::Location &location, const QString &description) const
- { compiler->recordError(location, description); }
- void recordError(const QQmlCompileError &error)
- { compiler->recordError(error); }
-
- QV4::ResolvedTypeReference *resolvedType(int id) const
- { return compiler->resolvedType(id); }
- bool containsResolvedType(int id) const
- { return compiler->resolvedTypes->contains(id); }
- QV4::ResolvedTypeReferenceMap::iterator insertResolvedType(
- int id, QV4::ResolvedTypeReference *value)
- { return compiler->resolvedTypes->insert(id, value); }
-
- QQmlTypeCompiler *compiler;
-};
-
-// "Converts" signal expressions to full-fleged function declarations with
-// parameters taken from the signal declarations
-// It also updates the QV4::CompiledData::Binding objects to set the property name
-// to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag.
-struct SignalHandlerConverter : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(SignalHandlerConverter)
-public:
- SignalHandlerConverter(QQmlTypeCompiler *typeCompiler);
-
- bool convertSignalHandlerExpressionsToFunctionDeclarations();
-
-private:
- bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
-
- QQmlEnginePrivate *enginePrivate;
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlImports *imports;
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QSet<QString> &illegalNames;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-// ### This will go away when the codegen resolves all enums to constant expressions
-// and we replace the constant expression with a literal binding instead of using
-// a script.
-class QQmlEnumTypeResolver : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlEnumTypeResolver)
-public:
- QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler);
-
- bool resolveEnumBindings();
-
-private:
- bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject);
- bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject)
- {
- return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject);
- }
- bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
- const QQmlPropertyData *prop,
- QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
-
-
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- const QQmlImports *imports;
-};
-
-class QQmlCustomParserScriptIndexer: public QQmlCompilePass
-{
-public:
- QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler);
-
- void annotateBindingsWithScriptStrings();
-
-private:
- void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false);
-
- const QVector<QmlIR::Object*> &qmlObjects;
- const QHash<int, QQmlCustomParser*> &customParsers;
-};
-
-// Annotate properties bound to aliases with a flag
-class QQmlAliasAnnotator : public QQmlCompilePass
-{
-public:
- QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler);
-
- void annotateBindingsToAliases();
-private:
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-class QQmlScriptStringScanner : public QQmlCompilePass
-{
-public:
- QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler);
-
- void scan();
-
-private:
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-class QQmlComponentAndAliasResolver : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
-public:
- QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler);
-
- bool resolve();
-
-protected:
- void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
- bool collectIdsAndAliases(int objectIndex);
- bool resolveAliases(int componentIndex);
- void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
-
- enum AliasResolutionResult {
- NoAliasResolved,
- SomeAliasesResolved,
- AllAliasesResolved
- };
-
- AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error);
-
- QQmlEnginePrivate *enginePrivate;
- QQmlJS::MemoryPool *pool;
-
- QVector<QmlIR::Object*> *qmlObjects;
-
- // indices of the objects that are actually Component {}
- QVector<quint32> componentRoots;
-
- // Deliberate choice of map over hash here to ensure stable generated output.
- QMap<int, int> _idToObjectIndex;
- QVector<int> _objectsWithAliases;
-
- QQmlPropertyCacheVector propertyCaches;
-};
-
-class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
-{
-public:
- QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
-
- bool scanObject();
-
-private:
- bool scanObject(int objectIndex);
-
- QVector<QmlIR::Object*> *qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- const QHash<int, QQmlCustomParser*> &customParsers;
-
- bool _seenObjectWithId;
-};
-
-// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
-class QQmlJSCodeGenerator : public QQmlCompilePass
-{
-public:
- QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen);
-
- bool generateCodeForComponents();
-
-private:
- bool compileComponent(int componentRoot);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
-
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- QmlIR::JSCodeGen * const v4CodeGen;
-};
-
-class QQmlDefaultPropertyMerger : public QQmlCompilePass
-{
-public:
- QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler);
-
- void mergeDefaultProperties();
-
-private:
- void mergeDefaultProperties(int objectIndex);
-
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLTYPECOMPILER_P_H
diff --git a/src/qml/compiler/qqmlirloader_p.h b/src/qml/compiler/qv4alloca_p.h
index aa303c923f..65c3e4d65a 100644
--- a/src/qml/compiler/qqmlirloader_p.h
+++ b/src/qml/compiler/qv4alloca_p.h
@@ -1,9 +1,9 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the tools applications of the Qt Toolkit.
+** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLIRLOADER_P_H
-#define QQMLIRLOADER_P_H
+#ifndef QV4_ALLOCA_H
+#define QV4_ALLOCA_H
//
// W A R N I N G
@@ -51,31 +51,58 @@
// We mean it.
//
-#include <private/qv4compileddata_p.h>
-#include <private/qqmljsmemorypool_p.h>
+#include <QtCore/private/qglobal_p.h>
-QT_BEGIN_NAMESPACE
+#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)
-namespace QmlIR {
-struct Document;
-struct Object;
-}
+#if QT_CONFIG(alloca)
-struct Q_QML_PRIVATE_EXPORT QQmlIRLoader {
- QQmlIRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
+#define Q_ALLOCA_DECLARE(type, name) \
+ type *name = 0
- void load();
+#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:
- QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
+ void *m_data;
+};
+QT_END_NAMESPACE
- template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
+#define Q_ALLOCA_DECLARE(type, name) \
+ Qt_AllocaWrapper _qt_alloca_##name; \
+ type *name = nullptr
- const QV4::CompiledData::Unit *unit;
- QmlIR::Document *output;
- QQmlJS::MemoryPool *pool;
-};
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ _qt_alloca_##name.allocate(size); \
+ name = static_cast<type*>(_qt_alloca_##name.data())
-QT_END_NAMESPACE
+#endif
-#endif // QQMLIRLOADER_P_H
+#endif
diff --git a/src/qml/compiler/qqmlpropertyresolver_p.h b/src/qml/compiler/qv4calldata_p.h
index df857f242e..5a5280cb86 100644
--- a/src/qml/compiler/qqmlpropertyresolver_p.h
+++ b/src/qml/compiler/qv4calldata_p.h
@@ -3,7 +3,7 @@
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the tools applications of the Qt Toolkit.
+** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLPROPERTYRESOLVER_P_H
-#define QQMLPROPERTYRESOLVER_P_H
+#ifndef QV4CALLDATA_P_H
+#define QV4CALLDATA_P_H
//
// W A R N I N G
@@ -51,37 +51,73 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmlrefcount_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
-struct Q_QML_EXPORT QQmlPropertyResolver
+namespace QV4 {
+
+struct CallData
{
- QQmlPropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
- : cache(cache)
- {}
+ enum Offsets {
+ Function = 0,
+ Context = 1,
+ Accumulator = 2,
+ This = 3,
+ NewTarget = 4,
+ Argc = 5,
- QQmlPropertyData *property(int index) const
- {
- return cache->property(index);
+ 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();
}
- enum RevisionCheck {
- CheckRevision,
- IgnoreRevision
- };
+ void setArgc(int argc) {
+ Q_ASSERT(argc >= 0);
+ _argc.setInt_32(argc);
+ }
- QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr,
- RevisionCheck check = CheckRevision) const;
+ inline ReturnedValue argument(int i) const {
+ return i < argc() ? args[i].asReturnedValue()
+ : StaticValue::undefinedValue().asReturnedValue();
+ }
+
+ StaticValue args[1];
- // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
+ static Q_DECL_CONSTEXPR int HeaderSize()
+ {
+ return offsetof(CallData, args) / sizeof(QV4::StaticValue);
+ }
- QQmlRefPointer<QQmlPropertyCache> cache;
+ 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 // QQMLPROPERTYRESOLVER_P_H
+#endif // QV4CALLDATA_P_H
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp
deleted file mode 100644
index 350f6f9485..0000000000
--- a/src/qml/compiler/qv4compilationunitmapper.cpp
+++ /dev/null
@@ -1,62 +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$
-**
-****************************************************************************/
-
-#include "qv4compilationunitmapper_p.h"
-
-#include "qv4compileddata_p.h"
-#include <QFileInfo>
-#include <QDateTime>
-#include <QCoreApplication>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-CompilationUnitMapper::CompilationUnitMapper()
- : dataPtr(nullptr)
-{
-
-}
-
-CompilationUnitMapper::~CompilationUnitMapper()
-{
- close();
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
deleted file mode 100644
index 6768bc9596..0000000000
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qv4compilationunitmapper_p.h"
-
-#include <sys/mman.h>
-#include <functional>
-#include <private/qcore_unix_p.h>
-#include <QScopeGuard>
-#include <QDateTime>
-
-#include "qv4compileddata_p.h"
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- close();
-
- int fd = qt_safe_open(QFile::encodeName(cacheFileName).constData(), O_RDONLY);
- if (fd == -1) {
- *errorString = qt_error_string(errno);
- return nullptr;
- }
-
- auto cleanup = qScopeGuard([fd]{
- qt_safe_close(fd) ;
- });
-
- CompiledData::Unit header;
- qint64 bytesRead = qt_safe_read(fd, reinterpret_cast<char *>(&header), sizeof(header));
-
- if (bytesRead != sizeof(header)) {
- *errorString = QStringLiteral("File too small for the header fields");
- return nullptr;
- }
-
- if (!header.verifyHeader(sourceTimeStamp, errorString))
- return nullptr;
-
- // Data structure and qt version matched, so now we can access the rest of the file safely.
-
- length = static_cast<size_t>(lseek(fd, 0, SEEK_END));
-
- void *ptr = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, /*offset*/0);
- if (ptr == MAP_FAILED) {
- *errorString = qt_error_string(errno);
- return nullptr;
- }
- dataPtr = ptr;
-
- return reinterpret_cast<CompiledData::Unit*>(dataPtr);
-}
-
-void CompilationUnitMapper::close()
-{
- // Do not unmap the data here.
- if (dataPtr != nullptr) {
- // Do not unmap cache files that are built with the StaticData flag. That's the majority of
- // them and it's necessary to benefit from the QString literal optimization. There might
- // still be QString instances around that point into that memory area. The memory is backed
- // on the disk, so the kernel is free to release the pages and all that remains is the
- // address space allocation.
- if (!(reinterpret_cast<CompiledData::Unit*>(dataPtr)->flags & CompiledData::Unit::StaticData))
- munmap(dataPtr, length);
- }
- dataPtr = nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
deleted file mode 100644
index 779c1288fe..0000000000
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ /dev/null
@@ -1,128 +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$
-**
-****************************************************************************/
-
-#include "qv4compilationunitmapper_p.h"
-
-#include "qv4compileddata_p.h"
-#include <QScopeGuard>
-#include <QFileInfo>
-#include <QDateTime>
-#include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- close();
-
- // ### TODO: fix up file encoding/normalization/unc handling once QFileSystemEntry
- // is exported from QtCore.
- HANDLE handle =
-#if defined(Q_OS_WINRT)
- CreateFile2(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
- GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
- OPEN_EXISTING, nullptr);
-#else
- CreateFile(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
- GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
- nullptr);
-#endif
- if (handle == INVALID_HANDLE_VALUE) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- auto fileHandleCleanup = qScopeGuard([handle]{
- CloseHandle(handle);
- });
-
- CompiledData::Unit header;
- DWORD bytesRead;
- if (!ReadFile(handle, reinterpret_cast<char *>(&header), sizeof(header), &bytesRead, nullptr)) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- if (bytesRead != sizeof(header)) {
- *errorString = QStringLiteral("File too small for the header fields");
- return nullptr;
- }
-
- if (!header.verifyHeader(sourceTimeStamp, errorString))
- return nullptr;
-
- // Data structure and qt version matched, so now we can access the rest of the file safely.
-
- HANDLE fileMappingHandle = CreateFileMapping(handle, 0, PAGE_READONLY, 0, 0, 0);
- if (!fileMappingHandle) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- auto mappingCleanup = qScopeGuard([fileMappingHandle]{
- CloseHandle(fileMappingHandle);
- });
-
- dataPtr = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0);
- if (!dataPtr) {
- *errorString = qt_error_string(GetLastError());
- return nullptr;
- }
-
- return reinterpret_cast<CompiledData::Unit*>(dataPtr);
-}
-
-void CompilationUnitMapper::close()
-{
- if (dataPtr != nullptr) {
- // Do not unmap cache files that are built with the StaticData flag. That's the majority of
- // them and it's necessary to benefit from the QString literal optimization. There might
- // still be QString instances around that point into that memory area. The memory is backed
- // on the disk, so the kernel is free to release the pages and all that remains is the
- // address space allocation.
- if (!(reinterpret_cast<CompiledData::Unit*>(dataPtr)->flags & CompiledData::Unit::StaticData))
- UnmapViewOfFile(dataPtr);
- }
- dataPtr = nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 8722263b04..d8f293211e 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -44,9 +44,16 @@
#include <private/qv4alloca_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsast_p.h>
-#include <wtf/MathExtras.h>
#include <QCryptographicHash>
+// Efficient implementation that takes advantage of powers of two.
+static inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
+{
+ Q_ASSERT(divisor && !(divisor & (divisor - 1)));
+ const size_t remainderMask = divisor - 1;
+ return (x + remainderMask) & ~remainderMask;
+}
+
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
clear();
@@ -91,7 +98,7 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
- char *stringData = reinterpret_cast<char *>(stringTable) + WTF::roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
+ char *stringData = reinterpret_cast<char *>(stringTable) + roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
for (int i = backingUnitTableSize ; i < strings.size(); ++i) {
const int index = i - backingUnitTableSize;
stringTable[index] = stringData - dataStart;
@@ -393,7 +400,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
- quint32 currentOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, sizeof(*function)));
+ quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*function)));
function->nameIndex = getStringId(irFunction->name);
function->flags = 0;
@@ -543,7 +550,7 @@ void QV4::Compiler::JSUnitGenerator::writeBlock(char *b, QV4::Compiler::Context
{
QV4::CompiledData::Block *block = reinterpret_cast<QV4::CompiledData::Block *>(b);
- quint32 currentOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, sizeof(*block)));
+ quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*block)));
block->sizeOfLocalTemporalDeadZone = irBlock->sizeOfLocalTemporalDeadZone;
block->nLocals = irBlock->locals.size();
@@ -606,7 +613,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.constantTableSize = constants.size();
// Ensure we load constants from well-aligned addresses into for example SSE registers.
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(16, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(16, nextOffset));
unit.offsetToConstantTable = nextOffset;
nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
@@ -617,19 +624,19 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
*jsClassDataOffset = nextOffset;
nextOffset += jsClassData.size();
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.translationTableSize = translations.count();
unit.offsetToTranslationTable = nextOffset;
nextOffset += unit.translationTableSize * sizeof(CompiledData::TranslationData);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
const auto reserveExportTable = [&nextOffset](int count, quint32_le *tableSizePtr, quint32_le *offsetPtr) {
*tableSizePtr = count;
*offsetPtr = nextOffset;
nextOffset += count * sizeof(CompiledData::ExportEntry);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
};
reserveExportTable(module->localExportEntries.count(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
@@ -639,12 +646,12 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.importEntryTableSize = module->importEntries.count();
unit.offsetToImportEntryTable = nextOffset;
nextOffset += unit.importEntryTableSize * sizeof(CompiledData::ImportEntry);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.moduleRequestTableSize = module->moduleRequests.count();
unit.offsetToModuleRequestTable = nextOffset;
nextOffset += unit.moduleRequestTableSize * sizeof(uint);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
quint32 functionSize = 0;
for (int i = 0; i < module->functions.size(); ++i) {
@@ -684,7 +691,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
if (option == GenerateWithStringTable) {
unit.stringTableSize = stringTable.stringCount();
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.offsetToStringTable = nextOffset;
nextOffset += stringTable.sizeOfTableAndData();
} else {
diff --git a/src/qml/compiler/qv4executablecompilationunit.cpp b/src/qml/compiler/qv4executablecompilationunit.cpp
deleted file mode 100644
index c68f6a7cbf..0000000000
--- a/src/qml/compiler/qv4executablecompilationunit.cpp
+++ /dev/null
@@ -1,809 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#include "qv4executablecompilationunit_p.h"
-
-#include <private/qv4engine_p.h>
-#include <private/qv4regexp_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4qmlcontext_p.h>
-#include <private/qv4identifiertable_p.h>
-#include <private/qv4instr_moth_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qv4module_p.h>
-#include <private/qv4compilationunitmapper_p.h>
-
-#include <QtQml/qqmlfile.h>
-#include <QtQml/qqmlpropertymap.h>
-
-#include <QtCore/qdir.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qscopeguard.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-ExecutableCompilationUnit::ExecutableCompilationUnit() = default;
-
-ExecutableCompilationUnit::ExecutableCompilationUnit(
- CompiledData::CompilationUnit &&compilationUnit)
- : CompiledData::CompilationUnit(std::move(compilationUnit))
-{}
-
-ExecutableCompilationUnit::~ExecutableCompilationUnit()
-{
- unlink();
-}
-
-QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url)
-{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
-}
-
-static QString toString(QV4::ReturnedValue v)
-{
- Value val = Value::fromReturnedValue(v);
- QString result;
- if (val.isInt32())
- result = QLatin1String("int ");
- else if (val.isDouble())
- result = QLatin1String("double ");
- if (val.isEmpty())
- result += QLatin1String("empty");
- else
- result += val.toQStringNoThrow();
- return result;
-}
-
-static void dumpConstantTable(const StaticValue *constants, uint count)
-{
- QDebug d = qDebug();
- d.nospace() << right;
- for (uint i = 0; i < count; ++i) {
- d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": "
- << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
- }
-}
-
-QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
-{
- this->engine = engine;
- engine->compilationUnits.insert(this);
-
- Q_ASSERT(!runtimeStrings);
- Q_ASSERT(data);
- const quint32 stringCount = totalStringCount();
- runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*));
- // memset the strings to 0 in case a GC run happens while we're within the loop below
- memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*));
- for (uint i = 0; i < stringCount; ++i)
- runtimeStrings[i] = engine->newString(stringAt(i));
-
- runtimeRegularExpressions
- = new QV4::Value[data->regexpTableSize];
- // memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeRegularExpressions, 0,
- data->regexpTableSize * sizeof(QV4::Value));
- for (uint i = 0; i < data->regexpTableSize; ++i) {
- const CompiledData::RegExp *re = data->regexpAt(i);
- uint f = re->flags;
- const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
- runtimeRegularExpressions[i] = QV4::RegExp::create(
- engine, stringAt(re->stringIndex), flags);
- }
-
- if (data->lookupTableSize) {
- runtimeLookups = new QV4::Lookup[data->lookupTableSize];
- memset(runtimeLookups, 0, data->lookupTableSize * sizeof(QV4::Lookup));
- const CompiledData::Lookup *compiledLookups = data->lookupTable();
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup *l = runtimeLookups + i;
-
- CompiledData::Lookup::Type type
- = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags));
- if (type == CompiledData::Lookup::Type_Getter)
- l->getter = QV4::Lookup::getterGeneric;
- else if (type == CompiledData::Lookup::Type_Setter)
- l->setter = QV4::Lookup::setterGeneric;
- else if (type == CompiledData::Lookup::Type_GlobalGetter)
- l->globalGetter = QV4::Lookup::globalGetterGeneric;
- else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
- l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- l->nameIndex = compiledLookups[i].nameIndex;
- }
- }
-
- if (data->jsClassTableSize) {
- runtimeClasses
- = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize
- * sizeof(QV4::Heap::InternalClass *));
- // memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeClasses, 0,
- data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
- for (uint i = 0; i < data->jsClassTableSize; ++i) {
- int memberCount = 0;
- const CompiledData::JSClassMember *member
- = data->jsClassAt(i, &memberCount);
- runtimeClasses[i]
- = engine->internalClasses(QV4::ExecutionEngine::Class_Object);
- for (int j = 0; j < memberCount; ++j, ++member)
- runtimeClasses[i]
- = runtimeClasses[i]->addMember(
- engine->identifierTable->asPropertyKey(
- runtimeStrings[member->nameOffset]),
- member->isAccessor
- ? QV4::Attr_Accessor
- : QV4::Attr_Data);
- }
- }
-
- runtimeFunctions.resize(data->functionTableSize);
- for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
- const QV4::CompiledData::Function *compiledFunction = data->functionAt(i);
- runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction);
- }
-
- Scope scope(engine);
- Scoped<InternalClass> ic(scope);
-
- runtimeBlocks.resize(data->blockTableSize);
- for (int i = 0 ;i < runtimeBlocks.size(); ++i) {
- const QV4::CompiledData::Block *compiledBlock = data->blockAt(i);
- ic = engine->internalClasses(EngineBase::Class_CallContext);
-
- // first locals
- const quint32_le *localsIndices = compiledBlock->localsTable();
- for (quint32 j = 0; j < compiledBlock->nLocals; ++j)
- ic = ic->addMember(
- engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[j]]),
- Attr_NotConfigurable);
- runtimeBlocks[i] = ic->d();
- }
-
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
- if (showCode) {
- qDebug() << "=== Constant table";
- dumpConstantTable(constants, data->constantTableSize);
- qDebug() << "=== String table";
- for (uint i = 0, end = totalStringCount(); i < end; ++i)
- qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
- qDebug() << "=== Closure table";
- for (uint i = 0; i < data->functionTableSize; ++i)
- qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString();
- qDebug() << "root function at index "
- << (data->indexOfRootFunction != -1
- ? data->indexOfRootFunction : 0);
- }
-
- if (data->indexOfRootFunction != -1)
- return runtimeFunctions[data->indexOfRootFunction];
- else
- return nullptr;
-}
-
-Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const
-{
- Q_ASSERT(index < int(data->templateObjectTableSize));
- if (!templateObjects.size())
- templateObjects.resize(data->templateObjectTableSize);
- Heap::Object *o = templateObjects.at(index);
- if (o)
- return o;
-
- // create the template object
- Scope scope(engine);
- const CompiledData::TemplateObject *t = data->templateObjectAt(index);
- Scoped<ArrayObject> a(scope, engine->newArrayObject(t->size));
- Scoped<ArrayObject> raw(scope, engine->newArrayObject(t->size));
- ScopedValue s(scope);
- for (uint i = 0; i < t->size; ++i) {
- s = runtimeStrings[t->stringIndexAt(i)];
- a->arraySet(i, s);
- s = runtimeStrings[t->rawStringIndexAt(i)];
- raw->arraySet(i, s);
- }
-
- ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, raw, 1);
- a->defineReadonlyProperty(QStringLiteral("raw"), raw);
- ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, a, 1);
-
- templateObjects[index] = a->objectValue()->d();
- return templateObjects.at(index);
-}
-
-void ExecutableCompilationUnit::unlink()
-{
- if (engine)
- nextCompilationUnit.remove();
-
- if (isRegisteredWithEngine) {
- Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
- if (qmlEngine)
- qmlEngine->unregisterInternalCompositeType(this);
- QQmlMetaType::unregisterInternalCompositeType(this);
- isRegisteredWithEngine = false;
- }
-
- propertyCaches.clear();
-
- if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) {
- if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache)
- pc->release();
- }
-
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- }
- }
- }
-
- dependentScripts.clear();
-
- typeNameCache = nullptr;
-
- qDeleteAll(resolvedTypes);
- resolvedTypes.clear();
-
- engine = nullptr;
- qmlEngine = nullptr;
-
- delete [] runtimeLookups;
- runtimeLookups = nullptr;
-
- for (QV4::Function *f : qAsConst(runtimeFunctions))
- f->destroy();
- runtimeFunctions.clear();
-
- CompiledData::CompilationUnit::unlink();
-}
-
-void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack)
-{
- if (runtimeStrings) {
- for (uint i = 0, end = totalStringCount(); i < end; ++i)
- if (runtimeStrings[i])
- runtimeStrings[i]->mark(markStack);
- }
- if (runtimeRegularExpressions) {
- for (uint i = 0; i < data->regexpTableSize; ++i)
- Value::fromStaticValue(runtimeRegularExpressions[i]).mark(markStack);
- }
- if (runtimeClasses) {
- for (uint i = 0; i < data->jsClassTableSize; ++i)
- if (runtimeClasses[i])
- runtimeClasses[i]->mark(markStack);
- }
- for (QV4::Function *f : qAsConst(runtimeFunctions))
- if (f && f->internalClass)
- f->internalClass->mark(markStack);
- for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks))
- if (c)
- c->mark(markStack);
-
- for (QV4::Heap::Object *o : qAsConst(templateObjects))
- if (o)
- o->mark(markStack);
-
- if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i)
- runtimeLookups[i].markObjects(markStack);
- }
-
- if (auto mod = module())
- mod->mark(markStack);
-}
-
-IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex)
-{
- IdentifierHash namedObjectCache(engine);
- const CompiledData::Object *component = objectAt(componentObjectIndex);
- const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
- for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
- const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr);
- namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
- }
- return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
-}
-
-void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
-{
- this->qmlEngine = qmlEngine;
-
- // Add to type registry of composites
- if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
- QQmlMetaType::registerInternalCompositeType(this);
- qmlEngine->registerInternalCompositeType(this);
- } else {
- const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
- auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- if (typeRef->compilationUnit) {
- metaTypeId = typeRef->compilationUnit->metaTypeId;
- listMetaTypeId = typeRef->compilationUnit->listMetaTypeId;
- } else {
- metaTypeId = typeRef->type.typeId();
- listMetaTypeId = typeRef->type.qListTypeId();
- }
- }
-
- // Collect some data for instantiation later.
- int bindingCount = 0;
- int parserStatusCount = 0;
- int objectCount = 0;
- for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
- const QV4::CompiledData::Object *obj = objectAt(i);
- bindingCount += obj->nBindings;
- if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid()) {
- if (typeRef->type.parserStatusCast() != -1)
- ++parserStatusCount;
- }
- ++objectCount;
- if (typeRef->compilationUnit) {
- bindingCount += typeRef->compilationUnit->totalBindingsCount;
- parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
- objectCount += typeRef->compilationUnit->totalObjectCount;
- }
- }
- }
-
- totalBindingsCount = bindingCount;
- totalParserStatusCount = parserStatusCount;
- totalObjectCount = objectCount;
-}
-
-bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const
-{
- if (!dependencyHasher) {
- for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
- if (data->dependencyMD5Checksum[i] != 0)
- return false;
- }
- return true;
- }
- const QByteArray checksum = dependencyHasher();
- return checksum.size() == sizeof(data->dependencyMD5Checksum)
- && memcmp(data->dependencyMD5Checksum, checksum.constData(),
- sizeof(data->dependencyMD5Checksum)) == 0;
-}
-
-QStringList ExecutableCompilationUnit::moduleRequests() const
-{
- QStringList requests;
- requests.reserve(data->moduleRequestTableSize);
- for (uint i = 0; i < data->moduleRequestTableSize; ++i)
- requests << stringAt(data->moduleRequestTable()[i]);
- return requests;
-}
-
-Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
-{
- if (isESModule() && module())
- return module();
-
- if (data->indexOfRootFunction < 0)
- return nullptr;
-
- if (!this->engine)
- linkToEngine(engine);
-
- Scope scope(engine);
- Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(engine, this));
-
- if (isESModule())
- setModule(module->d());
-
- for (const QString &request: moduleRequests()) {
- auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
- if (engine->hasException)
- return nullptr;
- dependentModuleUnit->instantiate(engine);
- }
-
- ScopedString importName(scope);
-
- const uint importCount = data->importEntryTableSize;
- if (importCount > 0) {
- imports = new const StaticValue *[importCount];
- memset(imports, 0, importCount * sizeof(StaticValue *));
- }
- for (uint i = 0; i < importCount; ++i) {
- const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- importName = runtimeStrings[entry.importName];
- const Value *valuePtr = dependentModuleUnit->resolveExport(importName);
- if (!valuePtr) {
- QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
- referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
- return nullptr;
- }
- imports[i] = valuePtr;
- }
-
- for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- if (!dependentModuleUnit)
- return nullptr;
-
- ScopedString importName(scope, runtimeStrings[entry.importName]);
- if (!dependentModuleUnit->resolveExport(importName)) {
- QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
- referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
- return nullptr;
- }
- }
-
- return module->d();
-}
-
-const Value *ExecutableCompilationUnit::resolveExportRecursively(
- QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet)
-{
- if (!module())
- return nullptr;
-
- for (const auto &entry: *resolveSet)
- if (entry.module == this && entry.exportName->isEqualTo(exportName))
- return nullptr;
-
- (*resolveSet) << ResolveSetEntry(this, exportName);
-
- if (exportName->toQString() == QLatin1String("*"))
- return &module()->self;
-
- Scope scope(engine);
-
- if (auto localExport = lookupNameInExportTable(
- data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) {
- ScopedString localName(scope, runtimeStrings[localExport->localName]);
- uint index = module()->scope->internalClass->indexOfValueOrGetter(localName->toPropertyKey());
- if (index == UINT_MAX)
- return nullptr;
- if (index >= module()->scope->locals.size)
- return &(imports[index - module()->scope->locals.size]->asValue<Value>());
- return &module()->scope->locals[index];
- }
-
- if (auto indirectExport = lookupNameInExportTable(
- data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) {
- auto dependentModuleUnit = engine->loadModule(urlAt(indirectExport->moduleRequest), this);
- if (!dependentModuleUnit)
- return nullptr;
- ScopedString importName(scope, runtimeStrings[indirectExport->importName]);
- return dependentModuleUnit->resolveExportRecursively(importName, resolveSet);
- }
-
-
- if (exportName->toQString() == QLatin1String("default"))
- return nullptr;
-
- const Value *starResolution = nullptr;
-
- for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- if (!dependentModuleUnit)
- return nullptr;
-
- const Value *resolution = dependentModuleUnit->resolveExportRecursively(exportName, resolveSet);
- // ### handle ambiguous
- if (resolution) {
- if (!starResolution) {
- starResolution = resolution;
- continue;
- }
- if (resolution != starResolution)
- return nullptr;
- }
- }
-
- return starResolution;
-}
-
-const CompiledData::ExportEntry *ExecutableCompilationUnit::lookupNameInExportTable(
- const CompiledData::ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const
-{
- const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize;
- auto matchingExport = std::lower_bound(firstExportEntry, lastExportEntry, name, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) {
- return stringAt(lhs.exportName) < name->toQString();
- });
- if (matchingExport == lastExportEntry || stringAt(matchingExport->exportName) != name->toQString())
- return nullptr;
- return matchingExport;
-}
-
-void ExecutableCompilationUnit::getExportedNamesRecursively(
- QStringList *names, QVector<const ExecutableCompilationUnit*> *exportNameSet,
- bool includeDefaultExport) const
-{
- if (exportNameSet->contains(this))
- return;
- exportNameSet->append(this);
-
- const auto append = [names, includeDefaultExport](const QString &name) {
- if (!includeDefaultExport && name == QLatin1String("default"))
- return;
- names->append(name);
- };
-
- for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i];
- append(stringAt(entry.exportName));
- }
-
- for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
- append(stringAt(entry.exportName));
- }
-
- for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
- const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- if (!dependentModuleUnit)
- return;
- dependentModuleUnit->getExportedNamesRecursively(names, exportNameSet, /*includeDefaultExport*/false);
- }
-}
-
-void ExecutableCompilationUnit::evaluate()
-{
- QV4::Scope scope(engine);
- QV4::Scoped<Module> mod(scope, module());
- mod->evaluate();
-}
-
-void ExecutableCompilationUnit::evaluateModuleRequests()
-{
- for (const QString &request: moduleRequests()) {
- auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
- if (engine->hasException)
- return;
- dependentModuleUnit->evaluate();
- if (engine->hasException)
- return;
- }
-}
-
-bool ExecutableCompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
-
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
-
- const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) };
- for (const QString &cachePath : cachePaths) {
- CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString);
- if (!mappedUnit)
- continue;
-
- const CompiledData::Unit * const oldDataPtr
- = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data
- : nullptr;
- const CompiledData::Unit *oldData = data;
- auto dataPtrRevert = qScopeGuard([this, oldData](){
- setUnitData(oldData);
- });
- setUnitData(mappedUnit);
-
- if (data->sourceFileIndex != 0
- && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- continue;
- }
-
- dataPtrRevert.dismiss();
- free(const_cast<CompiledData::Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
- }
-
- return false;
-}
-
-bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
-{
- if (data->sourceTimeStamp == 0) {
- *errorString = QStringLiteral("Missing time stamp for source file");
- return false;
- }
-
- if (!QQmlFile::isLocalFile(unitUrl)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
-
- return CompilationUnit::saveToDisk(localCacheFilePath(unitUrl), errorString);
-}
-
-/*!
-Returns the property cache, if one alread exists. The cache is not referenced.
-*/
-QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::propertyCache() const
-{
- if (type.isValid())
- return typePropertyCache;
- else
- return compilationUnit->rootPropertyCache();
-}
-
-/*!
-Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
-*/
-QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
-{
- if (typePropertyCache) {
- return typePropertyCache;
- } else if (type.isValid()) {
- typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion);
- return typePropertyCache;
- } else {
- return compilationUnit->rootPropertyCache();
- }
-}
-
-bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine)
-{
- if (type.isValid()) {
- bool ok = false;
- hash->addData(createPropertyCache(engine)->checksum(&ok));
- return ok;
- }
- if (!compilationUnit)
- return false;
- hash->addData(compilationUnit->data->md5Checksum,
- sizeof(compilationUnit->data->md5Checksum));
- return true;
-}
-
-template <typename T>
-bool qtTypeInherits(const QMetaObject *mo) {
- while (mo) {
- if (mo == &T::staticMetaObject)
- return true;
- mo = mo->superClass();
- }
- return false;
-}
-
-void ResolvedTypeReference::doDynamicTypeCheck()
-{
- const QMetaObject *mo = nullptr;
- if (typePropertyCache)
- mo = typePropertyCache->firstCppMetaObject();
- else if (type.isValid())
- mo = type.metaObject();
- else if (compilationUnit)
- mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
- isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
-}
-
-bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
-{
- for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
- if (!it.value()->addToHash(hash, engine))
- return false;
- }
-
- return true;
-}
-
-QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const
-{
- using namespace CompiledData;
- switch (binding->type) {
- case Binding::Type_Script:
- case Binding::Type_String:
- return stringAt(binding->stringIndex);
- case Binding::Type_Null:
- return QStringLiteral("null");
- case Binding::Type_Boolean:
- return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
- case Binding::Type_Number:
- return QString::number(bindingValueAsNumber(binding));
- case Binding::Type_Invalid:
- return QString();
-#if !QT_CONFIG(translation)
- case Binding::Type_TranslationById:
- case Binding::Type_Translation:
- return unit->stringAt(
- unit->data->translations()[binding->value.translationDataIndex].stringIndex);
-#else
- case Binding::Type_TranslationById: {
- const TranslationData &translation
- = data->translations()[binding->value.translationDataIndex];
- QByteArray id = stringAt(translation.stringIndex).toUtf8();
- return qtTrId(id.constData(), translation.number);
- }
- case Binding::Type_Translation: {
- const TranslationData &translation
- = data->translations()[binding->value.translationDataIndex];
- // This code must match that in the qsTr() implementation
- const QString &path = fileName();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
- : QStringRef();
- QByteArray contextUtf8 = context.toUtf8();
- QByteArray comment = stringAt(translation.commentIndex).toUtf8();
- QByteArray text = stringAt(translation.stringIndex).toUtf8();
- return QCoreApplication::translate(contextUtf8.constData(), text.constData(),
- comment.constData(), translation.number);
- }
-#endif
- default:
- break;
- }
- return QString();
-}
-
-QString ExecutableCompilationUnit::bindingValueAsScriptString(
- const CompiledData::Binding *binding) const
-{
- return (binding->type == CompiledData::Binding::Type_String)
- ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
- : bindingValueAsString(binding);
-}
-
-} // namespace QV4
-
-QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4executablecompilationunit_p.h b/src/qml/compiler/qv4executablecompilationunit_p.h
deleted file mode 100644
index 4e3aadf28a..0000000000
--- a/src/qml/compiler/qv4executablecompilationunit_p.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 QV4EXECUTABLECOMPILATIONUNIT_P_H
-#define QV4EXECUTABLECOMPILATIONUNIT_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/qv4compileddata_p.h>
-#include <private/qqmlrefcount_p.h>
-#include <private/qintrusivelist_p.h>
-#include <private/qqmlpropertycachevector_p.h>
-#include <private/qqmltype_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEnginePrivate;
-namespace QV4 {
-
-class CompilationUnitMapper;
-struct ResolvedTypeReference;
-// map from name index
-// While this could be a hash, a map is chosen here to provide a stable
-// order, which is used to calculating a check-sum on dependent meta-objects.
-struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
-{
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
-};
-
-class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit,
- public QQmlRefCount
-{
- Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit)
-public:
- friend class QQmlRefPointer<ExecutableCompilationUnit>;
-
- static QQmlRefPointer<ExecutableCompilationUnit> create(
- CompiledData::CompilationUnit &&compilationUnit)
- {
- return QQmlRefPointer<ExecutableCompilationUnit>(
- new ExecutableCompilationUnit(std::move(compilationUnit)),
- QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
- }
-
- static QQmlRefPointer<ExecutableCompilationUnit> create()
- {
- return QQmlRefPointer<ExecutableCompilationUnit>(
- new ExecutableCompilationUnit,
- QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
- }
-
- QIntrusiveListNode nextCompilationUnit;
- ExecutionEngine *engine = nullptr;
- QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
-
- // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
- // warnings about that code. They include any potential URL interceptions and thus represent the
- // "physical" location of the code.
- //
- // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
- // They are _not_ intercepted and thus represent the "logical" name for the code.
-
- QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QUrl finalUrl() const
- {
- if (m_finalUrl.isNull)
- m_finalUrl = QUrl(finalUrlString());
- return m_finalUrl;
- }
-
- QV4::Lookup *runtimeLookups = nullptr;
- QVector<QV4::Function *> runtimeFunctions;
- QVector<QV4::Heap::InternalClass *> runtimeBlocks;
- mutable QVector<QV4::Heap::Object *> templateObjects;
- mutable QQmlNullableValue<QUrl> m_url;
- mutable QQmlNullableValue<QUrl> m_finalUrl;
-
- // QML specific fields
- QQmlPropertyCacheVector propertyCaches;
- QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
-
- // index is object index. This allows fast access to the
- // property data when initializing bindings, avoiding expensive
- // lookups by string (property name).
- QVector<CompiledData::BindingPropertyData> bindingPropertyDataPerObject;
-
- // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
- // this is initialized on-demand by QQmlContextData
- QHash<int, IdentifierHash> namedObjectsPerComponentCache;
- inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
-
- void finalizeCompositeType(QQmlEnginePrivate *qmlEngine);
-
- int totalBindingsCount = 0; // Number of bindings used in this type
- int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
- int totalObjectCount = 0; // Number of objects explicitly instantiated
-
- QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
- ResolvedTypeReferenceMap resolvedTypes;
- ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
-
- bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
-
- int metaTypeId = -1;
- int listMetaTypeId = -1;
- bool isRegisteredWithEngine = false;
-
- QScopedPointer<CompilationUnitMapper> backingFile;
-
- // --- interface for QQmlPropertyCacheCreator
- using CompiledObject = CompiledData::Object;
- using CompiledFunction = CompiledData::Function;
-
- int objectCount() const { return qmlData->nObjects; }
- const CompiledObject *objectAt(int index) const
- {
- return qmlData->objectAt(index);
- }
-
- int importCount() const { return qmlData->nImports; }
- const CompiledData::Import *importAt(int index) const
- {
- return qmlData->importAt(index);
- }
-
- Heap::Object *templateObjectAt(int index) const;
-
- struct FunctionIterator
- {
- FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
- : unit(unit), object(object), index(index) {}
- const CompiledData::Unit *unit;
- const CompiledObject *object;
- int index;
-
- const CompiledFunction *operator->() const
- {
- return unit->functionAt(object->functionOffsetTable()[index]);
- }
-
- void operator++() { ++index; }
- bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
- bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
- };
-
- FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
- {
- return FunctionIterator(data, object, 0);
- }
-
- FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
- {
- return FunctionIterator(data, object, object->nFunctions);
- }
-
- bool isESModule() const
- {
- return data->flags & CompiledData::Unit::IsESModule;
- }
-
- bool isSharedLibrary() const
- {
- return data->flags & CompiledData::Unit::IsSharedLibrary;
- }
-
- QStringList moduleRequests() const;
- Heap::Module *instantiate(ExecutionEngine *engine);
- const Value *resolveExport(QV4::String *exportName)
- {
- QVector<ResolveSetEntry> resolveSet;
- return resolveExportRecursively(exportName, &resolveSet);
- }
-
- QStringList exportedNames() const
- {
- QStringList names;
- QVector<const ExecutableCompilationUnit*> exportNameSet;
- getExportedNamesRecursively(&names, &exportNameSet);
- names.sort();
- auto last = std::unique(names.begin(), names.end());
- names.erase(last, names.end());
- return names;
- }
-
- void evaluate();
- void evaluateModuleRequests();
-
- QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
- void unlink();
-
- void markObjects(MarkStack *markStack);
-
- bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
-
- static QString localCacheFilePath(const QUrl &url);
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
-
- QString bindingValueAsString(const CompiledData::Binding *binding) const;
- QString bindingValueAsScriptString(const CompiledData::Binding *binding) const;
- double bindingValueAsNumber(const CompiledData::Binding *binding) const
- {
- if (binding->type != CompiledData::Binding::Type_Number)
- return 0.0;
- return constants[binding->value.constantValueIndex].doubleValue();
- }
-
-protected:
- quint32 totalStringCount() const
- { return data->stringTableSize; }
-
-private:
- struct ResolveSetEntry
- {
- ResolveSetEntry() {}
- ResolveSetEntry(ExecutableCompilationUnit *module, QV4::String *exportName)
- : module(module), exportName(exportName) {}
- ExecutableCompilationUnit *module = nullptr;
- QV4::String *exportName = nullptr;
- };
-
- ExecutableCompilationUnit();
- ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit);
- ~ExecutableCompilationUnit();
-
- const Value *resolveExportRecursively(QV4::String *exportName,
- QVector<ResolveSetEntry> *resolveSet);
-
- QUrl urlAt(int index) const { return QUrl(stringAt(index)); }
-
- Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex);
- const CompiledData::ExportEntry *lookupNameInExportTable(
- const CompiledData::ExportEntry *firstExportEntry, int tableSize,
- QV4::String *name) const;
-
- void getExportedNamesRecursively(
- QStringList *names, QVector<const ExecutableCompilationUnit *> *exportNameSet,
- bool includeDefaultExport = true) const;
-};
-
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType type;
- QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
- QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
-
- void doDynamicTypeCheck();
-};
-
-IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
-{
- auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
- if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
- return createNamedObjectsPerComponent(componentObjectIndex);
- return *it;
-}
-
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4EXECUTABLECOMPILATIONUNIT_P_H
diff --git a/src/qml/compiler/qv4staticvalue_p.h b/src/qml/compiler/qv4staticvalue_p.h
new file mode 100644
index 0000000000..c6b4bdb158
--- /dev/null
+++ b/src/qml/compiler/qv4staticvalue_p.h
@@ -0,0 +1,548 @@
+/****************************************************************************
+**
+** 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
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4stringtoarrayindex_p.h
index 80f914c141..61bd988d1e 100644
--- a/src/qml/compiler/qv4compilationunitmapper_p.h
+++ b/src/qml/compiler/qv4stringtoarrayindex_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QV4COMPILATIONUNITMAPPER_H
-#define QV4COMPILATIONUNITMAPPER_H
+#ifndef QV4STRINGTOARRAYINDEX_P_H
+#define QV4STRINGTOARRAYINDEX_P_H
//
// W A R N I N G
@@ -51,35 +51,46 @@
// We mean it.
//
-#include <private/qv4global_p.h>
-#include <QFile>
+#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/qstring.h>
+#include <limits>
QT_BEGIN_NAMESPACE
namespace QV4 {
-namespace CompiledData {
-struct Unit;
-}
+inline uint charToUInt(const QChar *ch) { return ch->unicode(); }
+inline uint charToUInt(const char *ch) { return static_cast<unsigned char>(*ch); }
-class CompilationUnitMapper
+template <typename T>
+uint stringToArrayIndex(const T *ch, const T *end)
{
-public:
- CompilationUnitMapper();
- ~CompilationUnitMapper();
-
- CompiledData::Unit *open(const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
- void close();
+ 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();
-private:
-#if defined(Q_OS_UNIX)
- size_t length;
-#endif
- void *dataPtr;
-};
+ 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 // QV4COMPILATIONUNITMAPPER_H
+#endif // QV4STRINGTOARRAYINDEX_P_H
diff --git a/src/qml/compiler/qv4util_p.h b/src/qml/compiler/qv4util_p.h
new file mode 100644
index 0000000000..bd9758c1fb
--- /dev/null
+++ b/src/qml/compiler/qv4util_p.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** 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 QV4UTIL_H
+#define QV4UTIL_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/QBitArray>
+#include <algorithm>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+#if !defined(BROKEN_STD_VECTOR_BOOL_OR_BROKEN_STD_FIND)
+// Sanity:
+class BitVector
+{
+ std::vector<bool> bits;
+
+public:
+ BitVector(int size = 0, bool value = false)
+ : bits(size, value)
+ {}
+
+ void clear()
+ { bits = std::vector<bool>(bits.size(), false); }
+
+ void reserve(int size)
+ { bits.reserve(size); }
+
+ int size() const
+ {
+ Q_ASSERT(bits.size() < INT_MAX);
+ return static_cast<int>(bits.size());
+ }
+
+ void resize(int newSize)
+ { bits.resize(newSize); }
+
+ void resize(int newSize, bool newValue)
+ { bits.resize(newSize, newValue); }
+
+ void assign(int newSize, bool value)
+ { bits.assign(newSize, value); }
+
+ int findNext(int start, bool value, bool wrapAround) const
+ {
+ // The ++operator of std::vector<bool>::iterator in libc++ has a bug when using it on an
+ // iterator pointing to the last element. It will not be set to ::end(), but beyond
+ // that. (It will be set to the first multiple of the native word size that is bigger
+ // than size().)
+ //
+ // See http://llvm.org/bugs/show_bug.cgi?id=19663
+ //
+ // The work-around is to calculate the distance, and compare it to the size() to see if it's
+ // beyond the end, or take the minimum of the distance and the size.
+
+ size_t pos = std::distance(bits.begin(),
+ std::find(bits.begin() + start, bits.end(), value));
+ if (wrapAround && pos >= static_cast<size_t>(size()))
+ pos = std::distance(bits.begin(),
+ std::find(bits.begin(), bits.begin() + start, value));
+
+ pos = qMin(pos, static_cast<size_t>(size()));
+
+ Q_ASSERT(pos <= static_cast<size_t>(size()));
+ Q_ASSERT(pos < INT_MAX);
+
+ return static_cast<int>(pos);
+ }
+
+ bool at(int idx) const
+ { return bits.at(idx); }
+
+ void setBit(int idx)
+ { bits[idx] = true; }
+
+ void clearBit(int idx)
+ { bits[idx] = false; }
+};
+#else // Insanity:
+class BitVector
+{
+ QBitArray bits;
+
+public:
+ BitVector(int size = 0, bool value = false)
+ : bits(size, value)
+ {}
+
+ void clear()
+ { bits = QBitArray(bits.size(), false); }
+
+ void reserve(int size)
+ { Q_UNUSED(size); }
+
+ int size() const
+ { return bits.size(); }
+
+ void resize(int newSize)
+ { bits.resize(newSize); }
+
+ void resize(int newSize, bool newValue)
+ {
+ int oldSize = bits.size();
+ bits.resize(newSize);
+ bits.fill(newValue, oldSize, bits.size());
+ }
+
+ void assign(int newSize, bool value)
+ {
+ bits.resize(newSize);
+ bits.fill(value);
+ }
+
+ int findNext(int start, bool value, bool wrapAround) const
+ {
+ for (int i = start, ei = size(); i < ei; ++i) {
+ if (at(i) == value)
+ return i;
+ }
+
+ if (wrapAround) {
+ for (int i = 0, ei = start; i < ei; ++i) {
+ if (at(i) == value)
+ return i;
+ }
+ }
+
+ return size();
+ }
+
+ bool at(int idx) const
+ { return bits.at(idx); }
+
+ void setBit(int idx)
+ { bits[idx] = true; }
+
+ void clearBit(int idx)
+ { bits[idx] = false; }
+};
+#endif
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4UTIL_H