aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-12-10 18:07:26 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-12-18 14:23:29 +0100
commitd2e331dfa02475e773e51af6e7532951f4d1a233 (patch)
treed16f2ef9cfd363ff09d06fed70b226ccb212f3ca /src/qml
parent31211f1415f221ed1a974663fdde117fd6de357d (diff)
Allow JavaScript primitive type transformations inline in C++
We don't want to call into the engine just for adding two numbers. This implements the most common operators on primitive JavaScript values. More are to follow in the future. Change-Id: Id51a5af59a3af9fec78a2d8f293e59e6567e9204 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/.prev_CMakeLists.txt2
-rw-r--r--src/qml/CMakeLists.txt2
-rw-r--r--src/qml/common/common.pri4
-rw-r--r--src/qml/common/qjsnumbercoercion.cpp68
-rw-r--r--src/qml/common/qjsnumbercoercion.h118
-rw-r--r--src/qml/common/qv4staticvalue_p.h59
-rw-r--r--src/qml/jsapi/jsapi.pri2
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.cpp288
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.h569
-rw-r--r--src/qml/jsapi/qjsvalue.cpp27
-rw-r--r--src/qml/jsapi/qjsvalue.h3
-rw-r--r--src/qml/jsapi/qjsvalue_p.h8
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp2
-rw-r--r--src/qml/jsruntime/qv4value_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp2
15 files changed, 1099 insertions, 59 deletions
diff --git a/src/qml/.prev_CMakeLists.txt b/src/qml/.prev_CMakeLists.txt
index 6415b4cf6b..8c0534c846 100644
--- a/src/qml/.prev_CMakeLists.txt
+++ b/src/qml/.prev_CMakeLists.txt
@@ -85,6 +85,7 @@ qt_internal_add_module(Qml
../3rdparty/masm/yarr/YarrPattern.cpp ../3rdparty/masm/yarr/YarrPattern.h
../3rdparty/masm/yarr/YarrSyntaxChecker.cpp ../3rdparty/masm/yarr/YarrSyntaxChecker.h
../3rdparty/masm/yarr/YarrUnicodeProperties.h
+ common/qjsnumbercoercion.cpp common/qjsnumbercoercion.h
common/qqmlapiversion_p.h
common/qqmljsdiagnosticmessage_p.h
common/qqmljsfixedpoolarray_p.h
@@ -113,6 +114,7 @@ qt_internal_add_module(Qml
debugger/qqmlprofiler_p.h
inlinecomponentutils_p.h
jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h
+ jsapi/qjsprimitivevalue.cpp jsapi/qjsprimitivevalue.h
jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h
jsapi/qjsvalueiterator.cpp jsapi/qjsvalueiterator.h jsapi/qjsvalueiterator_p.h
jsruntime/qv4argumentsobject.cpp jsruntime/qv4argumentsobject_p.h
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index 223ab4004e..41ca9c80f5 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -86,6 +86,7 @@ qt_internal_add_module(Qml
../3rdparty/masm/yarr/YarrPattern.cpp ../3rdparty/masm/yarr/YarrPattern.h
../3rdparty/masm/yarr/YarrSyntaxChecker.cpp ../3rdparty/masm/yarr/YarrSyntaxChecker.h
../3rdparty/masm/yarr/YarrUnicodeProperties.h
+ common/qjsnumbercoercion.cpp common/qjsnumbercoercion.h
common/qqmlapiversion_p.h
common/qqmljsdiagnosticmessage_p.h
common/qqmljsfixedpoolarray_p.h
@@ -114,6 +115,7 @@ qt_internal_add_module(Qml
debugger/qqmlprofiler_p.h
inlinecomponentutils_p.h
jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h
+ jsapi/qjsprimitivevalue.cpp jsapi/qjsprimitivevalue.h
jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h
jsapi/qjsvalueiterator.cpp jsapi/qjsvalueiterator.h jsapi/qjsvalueiterator_p.h
jsruntime/qv4argumentsobject.cpp jsruntime/qv4argumentsobject_p.h
diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri
index b333c0f6d9..0456232162 100644
--- a/src/qml/common/common.pri
+++ b/src/qml/common/common.pri
@@ -24,6 +24,7 @@
}
HEADERS += \
+ $$PWD/qjsnumbercoercion.h \
$$PWD/qqmlapiversion_p.h \
$$PWD/qqmljsdiagnosticmessage_p.h \
$$PWD/qqmljsfixedpoolarray_p.h \
@@ -34,3 +35,6 @@ HEADERS += \
$$PWD/qv4compileddata_p.h \
$$PWD/qv4staticvalue_p.h \
$$PWD/qv4stringtoarrayindex_p.h
+
+SOURCES += \
+ $$PWD/qjsnumbercoercion.cpp
diff --git a/src/qml/common/qjsnumbercoercion.cpp b/src/qml/common/qjsnumbercoercion.cpp
new file mode 100644
index 0000000000..e0ff560eb1
--- /dev/null
+++ b/src/qml/common/qjsnumbercoercion.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "qjsnumbercoercion.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 6.1
+ \class QJSNumberCoercion
+ \internal
+
+ \brief Implements the JavaScript double-to-int coercion.
+ */
+
+/*!
+ \fn int QJSNumberCoercion::toInteger(double d)
+ \internal
+
+ Coerces the given \a d to a 32bit integer by JavaScript rules and returns
+ the result.
+ */
+
+/*!
+ \fn bool equals(double lhs, double rhs)
+ \internal
+
+ Compares \a lhs and \a rhs bit by bit without causing a compile warning.
+ Returns the \c true if they are equal, or \c false if not.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/common/qjsnumbercoercion.h b/src/qml/common/qjsnumbercoercion.h
new file mode 100644
index 0000000000..51dbe6beb5
--- /dev/null
+++ b/src/qml/common/qjsnumbercoercion.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 QJSNUMBERCOERCION_H
+#define QJSNUMBERCOERCION_H
+
+#include <QtCore/qglobal.h>
+#include <cstring>
+
+QT_BEGIN_NAMESPACE
+
+class QJSNumberCoercion
+{
+public:
+ static constexpr int toInteger(double d) {
+ int i = static_cast<int>(d);
+ if (equals(i, d))
+ return i;
+ return QJSNumberCoercion(d).toInteger();
+ }
+
+ static constexpr bool equals(double lhs, double rhs)
+ {
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_FLOAT_COMPARE
+ return lhs == rhs;
+ QT_WARNING_POP
+ }
+
+private:
+ constexpr QJSNumberCoercion(double dbl)
+ {
+ // the dbl == 0 path is guaranteed constexpr. The other one may or may not be, depending
+ // on whether and how the compiler inlines the memcpy.
+ // In order to declare the ctor constexpr we need one guaranteed constexpr path.
+ if (!equals(dbl, 0))
+ memcpy(&d, &dbl, sizeof(double));
+ }
+
+ constexpr int sign() const
+ {
+ return (d >> 63) ? -1 : 1;
+ }
+
+ constexpr bool isDenormal() const
+ {
+ return static_cast<int>((d << 1) >> 53) == 0;
+ }
+
+ constexpr int exponent() const
+ {
+ return static_cast<int>((d << 1) >> 53) - 1023;
+ }
+
+ constexpr quint64 significant() const
+ {
+ quint64 m = (d << 12) >> 12;
+ if (!isDenormal())
+ m |= (static_cast<quint64>(1) << 52);
+ return m;
+ }
+
+ constexpr int toInteger()
+ {
+ 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);
+ }
+ }
+
+ quint64 d = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QJSNUMBERCOERCION_H
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index 2a44dcf607..5c2cdcf56e 100644
--- a/src/qml/common/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -50,6 +50,8 @@
// We mean it.
//
+#include <qjsnumbercoercion.h>
+
#include <QtCore/private/qnumeric_p.h>
#include <cstring>
@@ -69,53 +71,6 @@ namespace QV4 {
// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
typedef quint64 ReturnedValue;
-struct Double {
- quint64 d;
-
- Double(double dbl) {
- memcpy(&d, &dbl, sizeof(double));
- }
-
- int sign() const {
- return (d >> 63) ? -1 : 1;
- }
-
- bool isDenormal() const {
- return static_cast<int>((d << 1) >> 53) == 0;
- }
-
- int exponent() const {
- return static_cast<int>((d << 1) >> 53) - 1023;
- }
-
- quint64 significant() const {
- quint64 m = (d << 12) >> 12;
- if (!isDenormal())
- m |= (static_cast<quint64>(1) << 52);
- return m;
- }
-
- static int toInt32(double d) {
- int i = static_cast<int>(d);
- if (i == d)
- return i;
- return Double(d).toInt32();
- }
-
- int toInt32() {
- int e = exponent() - 52;
- if (e < 0) {
- if (e <= -53)
- return 0;
- return sign() * static_cast<int>(significant() >> -e);
- } else {
- if (e > 31)
- return 0;
- return sign() * (static_cast<int>(significant()) << e);
- }
- }
-};
-
struct StaticValue
{
StaticValue() = default;
@@ -440,13 +395,15 @@ struct StaticValue
case Integer_Type:
return int_32();
case Double_Type:
- return Double::toInt32(doubleValue());
+ return QJSNumberCoercion::toInteger(doubleValue());
case Empty_Type:
case Undefined_Type:
case Managed_Type:
- break;
+ return 0; // Coercion of NaN to int, results in 0;
}
- return Double::toInt32(std::numeric_limits<double>::quiet_NaN());
+
+ Q_UNREACHABLE();
+ return 0;
}
ReturnedValue *data_ptr() { return &_val; }
@@ -488,7 +445,7 @@ struct StaticValue
static int toInt32(double d)
{
- return Double::toInt32(d);
+ return QJSNumberCoercion::toInteger(d);
}
static unsigned int toUInt32(double d)
diff --git a/src/qml/jsapi/jsapi.pri b/src/qml/jsapi/jsapi.pri
index f70588ec7b..f96f8c959b 100644
--- a/src/qml/jsapi/jsapi.pri
+++ b/src/qml/jsapi/jsapi.pri
@@ -1,11 +1,13 @@
SOURCES += \
$$PWD/qjsengine.cpp \
+ $$PWD/qjsprimitivevalue.cpp \
$$PWD/qjsvalue.cpp \
$$PWD/qjsvalueiterator.cpp \
HEADERS += \
$$PWD/qjsengine.h \
$$PWD/qjsengine_p.h \
+ $$PWD/qjsprimitivevalue.h \
$$PWD/qjsvalue.h \
$$PWD/qjsvalue_p.h \
$$PWD/qjsvalueiterator.h \
diff --git a/src/qml/jsapi/qjsprimitivevalue.cpp b/src/qml/jsapi/qjsprimitivevalue.cpp
new file mode 100644
index 0000000000..71fcf5f84a
--- /dev/null
+++ b/src/qml/jsapi/qjsprimitivevalue.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "qjsprimitivevalue.h"
+
+#include <QtQml/private/qv4runtime_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 6.1
+ \class QJSPrimitiveUndefined
+ \brief An empty marker type to signify the JavaScript Undefined type and its single value.
+ */
+
+/*!
+ \since 6.1
+ \class QJSPrimitiveNull
+ \brief An empty marker type to signify the JavaScript null value.
+ */
+
+/*!
+ \since 6.1
+ \class QJSPrimitiveValue
+
+ \brief The QJSPrimitiveValue class operates on primitive types in JavaScript semantics.
+
+ \ingroup qtjavascript
+ \inmodule QtQml
+
+ QJSPrimitiveValue supports most of the primitive types defined in the
+ \l{ECMA-262} standard, in particular Undefined, Boolean, Number, and String.
+ Additionally, you can store a JavaScript null in a QJSPrimitiveValue and as a
+ special case of Number, you can store an integer value.
+
+ All those values are stored immediately, without interacting with the
+ JavaScript heap. Therefore, you can pass QJSPrimitiveValues between different
+ JavaScript engines. In contrast to QJSManagedValue, there is also no danger
+ in destroying a QJSPrimitiveValue from a different thread than it was created
+ in. On the flip side, QJSPrimitiveValue does not hold a reference to any
+ JavaScript engine.
+
+ QJSPrimitiveValue implements the JavaScript arithmetic and comparison
+ operators on the supported types in JavaScript semantics. Types are coerced
+ like the JavaScript engine would coerce them if the operators were written
+ in a JavaScript expression.
+
+ The JavaScript Symbol type is not supported as it is of very limited utility
+ regarding arithmetic and comparison operators, the main purpose of
+ QJSPrimitiveValue. In particular, it causes an exception whenever you try to
+ coerce it to a number or a string, and we cannot throw exceptions without a
+ JavaScript Engine.
+ */
+
+/*!
+ \enum QJSPrimitiveValue::Type
+
+ This enum speicifies the types a QJSPrimitiveValue might contain.
+
+ \value Undefined The JavaScript Undefined value.
+ \value Null The JavaScript null value. This is in fact not a separate
+ JavaScript type but a special value of the Object type. As it is
+ very common and storable without JavaScript engine, it is still
+ supported.
+ \value Boolean A JavaScript Boolean value.
+ \value Integer An integer. This is a special case of the JavaScript Number
+ type. JavaScript does not have an actual integer type, but
+ the \l{ECMA-262} standard contains rules on how to transform a
+ Number in order to prepare it for certain operators that only
+ make sense on integers, in particular the bit shift operators.
+ QJSPrimitiveValue's Integer type represents the result of such
+ a transformation.
+ \value Double A JavaScript Number value.
+ \value String A JavaScript String value.
+ */
+
+/*!
+ \fn Type QJSPrimitiveValue::type() const
+
+ Returns the type of the QJSPrimitiveValue.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue()
+
+ Creates a QJSPrimitiveValue of type Undefined.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QJSPrimitiveUndefined undefined)
+
+ Creates a QJSPrimitiveValue of value \a undefined and type Undefined.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QJSPrimitiveNull null)
+
+ Creates a QJSPrimitiveValue of value \a null and type Null.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(bool value)
+
+ Creates a QJSPrimitiveValue of value \a value and type Boolean.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(int value)
+
+ Creates a QJSPrimitiveValue of value \a value and type Integer.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(double value)
+
+ Creates a QJSPrimitiveValue of value \a value and type Double.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QString value)
+
+ Creates a QJSPrimitiveValue of value \a value and type String.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::toBoolean() const
+
+ Returns the value coerced a boolean by JavaScript rules.
+ */
+
+/*!
+ \fn int QJSPrimitiveValue::toInteger() const
+
+ Returns the value coerced to an integral 32bit number by the rules JavaScript
+ would apply when preparing it for a bit shift operation.
+ */
+
+/*!
+ \fn double QJSPrimitiveValue::toDouble() const
+
+ Returns the value coerced to a JavaScript Number by JavaScript rules.
+ */
+
+/*!
+ \fn QString QJSPrimitiveValue::toString() const
+
+ Returns the value coerced to a JavaScript String by JavaScript rules.
+ */
+
+/*!
+ \fn QJSPrimitiveValue operator+(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Perfoms the JavaScript '+' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QJSPrimitiveValue operator-(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '-' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QJSPrimitiveValue operator*(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '*' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QJSPrimitiveValue operator/(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '/' operation between \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::strictlyEquals(const QJSPrimitiveValue &other) const
+
+ Performs the JavaScript '===' operation on this QJSPrimitiveValue and
+ \a other, and returns the result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::equals(const QJSPrimitiveValue &other) const
+
+ Performs the JavaScript '==' operation on this QJSPrimitiveValue and
+ \a other, and returns the result.
+ */
+
+/*!
+ \fn bool operator==(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '===' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool operator!=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '!==' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool operator<(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '<' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '>' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '<=' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '>=' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+QString QJSPrimitiveValue::toString(double d)
+{
+ QString result;
+ QV4::RuntimeHelpers::numberToString(&result, d);
+ return result;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/jsapi/qjsprimitivevalue.h b/src/qml/jsapi/qjsprimitivevalue.h
new file mode 100644
index 0000000000..1a12104a61
--- /dev/null
+++ b/src/qml/jsapi/qjsprimitivevalue.h
@@ -0,0 +1,569 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 QJSPRIMITIVEVALUE_H
+#define QJSPRIMITIVEVALUE_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qjsnumbercoercion.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qnumeric.h>
+
+#include <variant>
+
+QT_BEGIN_NAMESPACE
+
+struct QJSPrimitiveUndefined {};
+struct QJSPrimitiveNull {};
+
+class QJSPrimitiveValue
+{
+ template<typename Concrete>
+ struct StringNaNOperators
+ {
+ static constexpr double op(const QString &, QJSPrimitiveUndefined)
+ {
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ static constexpr double op(QJSPrimitiveUndefined, const QString &)
+ {
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ static double op(const QString &lhs, QJSPrimitiveNull) { return op(lhs, 0); }
+ static double op(QJSPrimitiveNull, const QString &rhs) { return op(0, rhs); }
+
+ template<typename T>
+ static double op(const QString &lhs, T rhs)
+ {
+ return Concrete::op(fromString(lhs).toDouble(), rhs);
+ }
+
+ template<typename T>
+ static double op(T lhs, const QString &rhs)
+ {
+ return Concrete::op(lhs, fromString(rhs).toDouble());
+ }
+
+ static double op(const QString &lhs, const QString &rhs)
+ {
+ return Concrete::op(fromString(lhs).toDouble(), fromString(rhs).toDouble());
+ }
+ };
+
+ struct AddOperators {
+ static constexpr double op(double lhs, double rhs) { return lhs + rhs; }
+ static bool opOverflow(int lhs, int rhs, int *result)
+ {
+ return qAddOverflow(lhs, rhs, result);
+ }
+
+ template<typename T>
+ static QString op(const QString &lhs, T rhs)
+ {
+ return lhs + QJSPrimitiveValue(rhs).toString();
+ }
+
+ template<typename T>
+ static QString op(T lhs, const QString &rhs)
+ {
+ return QJSPrimitiveValue(lhs).toString() + rhs;
+ }
+
+ static QString op(const QString &lhs, const QString &rhs) { return lhs + rhs; }
+ };
+
+ struct SubOperators : private StringNaNOperators<SubOperators> {
+ static constexpr double op(double lhs, double rhs) { return lhs - rhs; }
+ static bool opOverflow(int lhs, int rhs, int *result)
+ {
+ return qSubOverflow(lhs, rhs, result);
+ }
+
+ using StringNaNOperators::op;
+ };
+
+ struct MulOperators : private StringNaNOperators<MulOperators> {
+ static constexpr double op(double lhs, double rhs) { return lhs * rhs; }
+ static bool opOverflow(int lhs, int rhs, int *result)
+ {
+ return qMulOverflow(lhs, rhs, result);
+ }
+
+ using StringNaNOperators::op;
+ };
+
+ struct DivOperators : private StringNaNOperators<DivOperators> {
+ static constexpr double op(double lhs, double rhs) { return lhs / rhs; }
+ static constexpr bool opOverflow(int, int, int *)
+ {
+ return true;
+ }
+
+ using StringNaNOperators::op;
+ };
+
+public:
+ enum Type {
+ Undefined,
+ Null,
+ Boolean,
+ Integer,
+ Double,
+ String
+ };
+
+ constexpr Type type() const { return Type(d.index()); }
+
+ constexpr QJSPrimitiveValue() = default;
+ constexpr QJSPrimitiveValue(QJSPrimitiveUndefined undefined) : d(undefined) {}
+ constexpr QJSPrimitiveValue(QJSPrimitiveNull null) : d(null) {}
+ constexpr QJSPrimitiveValue(bool value) : d(value) {}
+ constexpr QJSPrimitiveValue(int value) : d(value) {}
+ constexpr QJSPrimitiveValue(double value) : d(value) {}
+ QJSPrimitiveValue(QString string) : d(std::move(string)) {}
+
+ constexpr bool toBoolean() const
+ {
+ switch (type()) {
+ case Undefined: return false;
+ case Null: return false;
+ case Boolean: return std::get<bool>(d);
+ case Integer: return std::get<int>(d) != 0;
+ case Double: {
+ const double v = std::get<double>(d);
+ return !QJSNumberCoercion::equals(v, 0) && !std::isnan(v);
+ }
+ case String: return !std::get<QString>(d).isEmpty();
+ }
+
+ return false;
+ }
+
+ constexpr int toInteger() const
+ {
+ switch (type()) {
+ case Undefined: return 0;
+ case Null: return 0;
+ case Boolean: return std::get<bool>(d);
+ case Integer: return std::get<int>(d);
+ case Double: return QJSNumberCoercion::toInteger(std::get<double>(d));
+ case String: return fromString(std::get<String>(d)).toInteger();
+ }
+
+ return 0;
+ }
+
+ constexpr double toDouble() const
+ {
+ switch (type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return 0;
+ case Boolean: return std::get<bool>(d);
+ case Integer: return std::get<int>(d);
+ case Double: return std::get<double>(d);
+ case String: return fromString(std::get<String>(d)).toDouble();
+ }
+
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ QString toString() const
+ {
+ switch (type()) {
+ case Undefined: return QStringLiteral("undefined");
+ case Null: return QStringLiteral("null");
+ case Boolean: return std::get<bool>(d) ? QStringLiteral("true") : QStringLiteral("false");
+ case Integer: return QString::number(std::get<int>(d));
+ case Double: {
+ const double result = std::get<double>(d);
+ if (std::isnan(result))
+ return QStringLiteral("NaN");
+ if (std::isfinite(result))
+ return toString(result);
+ if (result > 0)
+ return QStringLiteral("Infinity");
+ return QStringLiteral("-Infinity");
+ }
+ case String: return std::get<QString>(d);
+ }
+
+ Q_UNREACHABLE();
+ return QString();
+ }
+
+ friend inline QJSPrimitiveValue operator+(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<AddOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator-(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<SubOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator*(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<MulOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator/(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<DivOperators>(lhs, rhs);
+ }
+
+ constexpr bool strictlyEquals(const QJSPrimitiveValue &other) const
+ {
+ const Type myType = type();
+ const Type otherType = other.type();
+
+ if (myType != otherType) {
+ // int -> double promotion is OK in strict mode
+ if (myType == Double && otherType == Integer)
+ return strictlyEquals(double(other.asInteger()));
+ if (myType == Integer && otherType == Double)
+ return QJSPrimitiveValue(double(asInteger())).strictlyEquals(other);
+ return false;
+ }
+
+ switch (myType) {
+ case Undefined:
+ case Null:
+ return true;
+ case Boolean:
+ return asBoolean() == other.asBoolean();
+ case Integer:
+ return asInteger() == other.asInteger();
+ case Double: {
+ const double l = asDouble();
+ const double r = other.asDouble();
+ if (std::isnan(l) || std::isnan(r))
+ return false;
+ if (qIsNull(l) && qIsNull(r))
+ return true;
+ return QJSNumberCoercion::equals(l, r);
+ }
+ case String:
+ return asString() == other.asString();
+ }
+
+ return false;
+ }
+
+ // Loose operator==, in contrast to strict ===
+ constexpr bool equals(const QJSPrimitiveValue &other) const
+ {
+ const Type myType = type();
+ const Type otherType = other.type();
+
+ if (myType == otherType)
+ return strictlyEquals(other);
+
+ switch (myType) {
+ case Undefined:
+ return otherType == Null;
+ case Null:
+ return otherType == Undefined;
+ case Boolean:
+ return QJSPrimitiveValue(int(asBoolean())).equals(other);
+ case Integer:
+ // prefer rhs bool -> int promotion over promoting both to double
+ return otherType == Boolean
+ ? QJSPrimitiveValue(asInteger()).equals(int(other.asBoolean()))
+ : QJSPrimitiveValue(double(asInteger())).equals(other);
+ case Double:
+ // Promote the other side to double (or recognize lhs as undefined/null)
+ return other.equals(*this);
+ case String:
+ return fromString(asString()).parsedEquals(other);
+ }
+
+ return false;
+ }
+
+ friend constexpr inline bool operator==(const QJSPrimitiveValue &lhs, const
+ QJSPrimitiveValue &rhs)
+ {
+ return lhs.strictlyEquals(rhs);
+ }
+
+ friend constexpr inline bool operator!=(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return !lhs.strictlyEquals(rhs);
+ }
+
+ friend constexpr inline bool operator<(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ switch (lhs.type()) {
+ case Undefined:
+ return false;
+ case Null: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return false;
+ case Boolean: return 0 < int(rhs.asBoolean());
+ case Integer: return 0 < rhs.asInteger();
+ case Double: return double(0) < rhs.asDouble();
+ case String: return double(0) < rhs.toDouble();
+ }
+ break;
+ }
+ case Boolean: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return int(lhs.asBoolean()) < 0;
+ case Boolean: return lhs.asBoolean() < rhs.asBoolean();
+ case Integer: return int(lhs.asBoolean()) < rhs.asInteger();
+ case Double: return double(lhs.asBoolean()) < rhs.asDouble();
+ case String: return double(lhs.asBoolean()) < rhs.toDouble();
+ }
+ break;
+ }
+ case Integer: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return lhs.asInteger() < 0;
+ case Boolean: return lhs.asInteger() < int(rhs.asBoolean());
+ case Integer: return lhs.asInteger() < rhs.asInteger();
+ case Double: return double(lhs.asInteger()) < rhs.asDouble();
+ case String: return double(lhs.asInteger()) < rhs.toDouble();
+ }
+ break;
+ }
+ case Double: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return lhs.asDouble() < double(0);
+ case Boolean: return lhs.asDouble() < double(rhs.asBoolean());
+ case Integer: return lhs.asDouble() < double(rhs.asInteger());
+ case Double: return lhs.asDouble() < rhs.asDouble();
+ case String: return lhs.asDouble() < rhs.toDouble();
+ }
+ break;
+ }
+ case String: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return lhs.toDouble() < double(0);
+ case Boolean: return lhs.toDouble() < double(rhs.asBoolean());
+ case Integer: return lhs.toDouble() < double(rhs.asInteger());
+ case Double: return lhs.toDouble() < rhs.asDouble();
+ case String: return lhs.asString() < rhs.asString();
+ }
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ friend constexpr inline bool operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ return rhs < lhs;
+ }
+
+ friend constexpr inline bool operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ if (lhs.type() == String) {
+ if (rhs.type() == String)
+ return lhs.asString() <= rhs.asString();
+ else
+ return fromString(lhs.asString()) <= rhs;
+ }
+ if (rhs.type() == String)
+ return lhs <= fromString(rhs.asString());
+
+ if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
+ return false;
+ return !(lhs > rhs);
+ }
+
+ friend constexpr inline bool operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ if (lhs.type() == String) {
+ if (rhs.type() == String)
+ return lhs.asString() >= rhs.asString();
+ else
+ return fromString(lhs.asString()) >= rhs;
+ }
+ if (rhs.type() == String)
+ return lhs >= fromString(rhs.asString());
+
+ if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
+ return false;
+ return !(lhs < rhs);
+ }
+
+private:
+ friend class QJSValue;
+
+ constexpr bool asBoolean() const { return std::get<bool>(d); }
+ constexpr int asInteger() const { return std::get<int>(d); }
+ constexpr double asDouble() const { return std::get<double>(d); }
+ QString asString() const { return std::get<QString>(d); }
+
+ constexpr bool parsedEquals(const QJSPrimitiveValue &other) const
+ {
+ return type() != Undefined && equals(other);
+ }
+
+ static QJSPrimitiveValue fromString(const QString &string)
+ {
+ bool ok;
+ const int intValue = string.toInt(&ok);
+ if (ok)
+ return intValue;
+
+ const double doubleValue = string.toDouble(&ok);
+ if (ok)
+ return doubleValue;
+ if (string == QStringLiteral("Infinity"))
+ return std::numeric_limits<double>::infinity();
+ if (string == QStringLiteral("-Infinity"))
+ return -std::numeric_limits<double>::infinity();
+ if (string == QStringLiteral("NaN"))
+ return std::numeric_limits<double>::quiet_NaN();
+ return QJSPrimitiveUndefined();
+ }
+
+ static Q_QML_EXPORT QString toString(double d);
+
+ template<typename Operators, typename Lhs, typename Rhs>
+ static QJSPrimitiveValue operateOnIntegers(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ int result;
+ if (Operators::opOverflow(std::get<Lhs>(lhs.d), std::get<Rhs>(rhs.d), &result))
+ return Operators::op(std::get<Lhs>(lhs.d), std::get<Rhs>(rhs.d));
+ return result;
+ }
+
+ template<typename Operators>
+ static QJSPrimitiveValue operate(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ switch (lhs.type()) {
+ case Undefined:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return std::numeric_limits<double>::quiet_NaN();
+ case Boolean: return std::numeric_limits<double>::quiet_NaN();
+ case Integer: return std::numeric_limits<double>::quiet_NaN();
+ case Double: return std::numeric_limits<double>::quiet_NaN();
+ case String: return Operators::op(QJSPrimitiveUndefined(), rhs.asString());
+ }
+ break;
+ case Null:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return operateOnIntegers<Operators, int, int>(0, 0);
+ case Boolean: return operateOnIntegers<Operators, int, bool>(0, rhs);
+ case Integer: return operateOnIntegers<Operators, int, int>(0, rhs);
+ case Double: return Operators::op(0, rhs.asDouble());
+ case String: return Operators::op(QJSPrimitiveNull(), rhs.asString());
+ }
+ break;
+ case Boolean:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return operateOnIntegers<Operators, bool, int>(lhs, 0);
+ case Boolean: return operateOnIntegers<Operators, bool, bool>(lhs, rhs);
+ case Integer: return operateOnIntegers<Operators, bool, int>(lhs, rhs);
+ case Double: return Operators::op(lhs.asBoolean(), rhs.asDouble());
+ case String: return Operators::op(lhs.asBoolean(), rhs.asString());
+ }
+ break;
+ case Integer:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return operateOnIntegers<Operators, int, int>(lhs, 0);
+ case Boolean: return operateOnIntegers<Operators, int, bool>(lhs, rhs);
+ case Integer: return operateOnIntegers<Operators, int, int>(lhs, rhs);
+ case Double: return Operators::op(lhs.asInteger(), rhs.asDouble());
+ case String: return Operators::op(lhs.asInteger(), rhs.asString());
+ }
+ break;
+ case Double:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return Operators::op(lhs.asDouble(), 0);
+ case Boolean: return Operators::op(lhs.asDouble(), rhs.asBoolean());
+ case Integer: return Operators::op(lhs.asDouble(), rhs.asInteger());
+ case Double: return Operators::op(lhs.asDouble(), rhs.asDouble());
+ case String: return Operators::op(lhs.asDouble(), rhs.asString());
+ }
+ break;
+ case String:
+ switch (rhs.type()) {
+ case Undefined: return Operators::op(lhs.asString(), QJSPrimitiveUndefined());
+ case Null: return Operators::op(lhs.asString(), QJSPrimitiveNull());
+ case Boolean: return Operators::op(lhs.asString(), rhs.asBoolean());
+ case Integer: return Operators::op(lhs.asString(), rhs.asInteger());
+ case Double: return Operators::op(lhs.asString(), rhs.asDouble());
+ case String: return Operators::op(lhs.asString(), rhs.asString());
+ }
+ break;
+ }
+
+ Q_UNREACHABLE();
+ return QJSPrimitiveUndefined();
+ }
+
+ constexpr bool isNanOrUndefined() const
+ {
+ switch (type()) {
+ case Undefined: return true;
+ case Double: return std::isnan(asDouble());
+ default: return false;
+ }
+ }
+
+ std::variant<QJSPrimitiveUndefined, QJSPrimitiveNull, bool, int, double, QString> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QJSPRIMITIVEVALUE_H
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index ad5ab95408..ce3ab0076b 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -42,6 +42,7 @@
#include <QtCore/qdatetime.h>
#include "qjsengine.h"
#include "qjsvalue.h"
+#include "qjsprimitivevalue.h"
#include "qjsvalue_p.h"
#include "qv4value_p.h"
#include "qv4object_p.h"
@@ -857,6 +858,32 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
return *this;
}
+QJSValue::QJSValue(QJSPrimitiveValue &&value)
+{
+ switch (value.type()) {
+ case QJSPrimitiveValue::Undefined:
+ d = QV4::Encode::undefined();
+ return;
+ case QJSPrimitiveValue::Null:
+ d = QV4::Encode::null();
+ return;
+ case QJSPrimitiveValue::Boolean:
+ d = QV4::Encode(value.asBoolean());
+ return;
+ case QJSPrimitiveValue::Integer:
+ d = QV4::Encode(value.asInteger());
+ return;
+ case QJSPrimitiveValue::Double:
+ d = QV4::Encode(value.asDouble());
+ return;
+ case QJSPrimitiveValue::String:
+ QJSValuePrivate::setString(this, std::move(std::get<QString>(value.d)));
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
static bool js_equal(const QString &string, const QV4::Value &value)
{
if (String *s = value.stringValue())
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index ad3c4ffd4d..393f1c960e 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -53,6 +53,7 @@ class QVariant;
class QObject;
struct QMetaObject;
class QDateTime;
+class QJSPrimitiveValue;
typedef QList<QJSValue> QJSValueList;
namespace QV4 {
@@ -107,6 +108,8 @@ public:
QJSValue &operator=(const QJSValue &other);
+ explicit QJSValue(QJSPrimitiveValue &&value);
+
bool isBool() const;
bool isNumber() const;
bool isNull() const;
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index 5533682144..9e371118cc 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -89,9 +89,9 @@ class Q_AUTOTEST_EXPORT QJSValuePrivate
return (m & IsString) ? reinterpret_cast<QString *>(m & ~IsString) : nullptr;
}
- static QV4::ReturnedValue encode(const QString &string)
+ static QV4::ReturnedValue encode(QString string)
{
- const quintptr m = quintptr(new QString(string)) | IsString;
+ const quintptr m = quintptr(new QString(std::move(string))) | IsString;
return encodeRawValue(m);
}
@@ -160,9 +160,9 @@ public:
return QV4::Encode::undefined();
}
- static void setString(QJSValue *jsval, const QString &s)
+ static void setString(QJSValue *jsval, QString s)
{
- jsval->d = encode(s);
+ jsval->d = encode(std::move(s));
}
static void setValue(QJSValue *jsval, const QV4::Value &v)
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index f425c6c87f..c816465d76 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -63,7 +63,7 @@ static inline int toInt32(Value v)
Q_ASSERT(v.isNumber());
if (v.isInteger())
return v.integerValue();
- return Double::toInt32(v.doubleValue());
+ return QJSNumberCoercion::toInteger(v.doubleValue());
}
static inline double toDouble(Value v)
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 530c8eaf27..44383689b4 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -434,9 +434,9 @@ inline int Value::toInt32() const
return int_32();
if (Q_LIKELY(isDouble()))
- return Double::toInt32(doubleValue());
+ return QJSNumberCoercion::toInteger(doubleValue());
- return Double::toInt32(toNumberImpl());
+ return QJSNumberCoercion::toInteger(toNumberImpl());
}
inline unsigned int Value::toUInt32() const
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 4815f5ad91..9fefa2a38c 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -425,7 +425,7 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
d = val.toNumberImpl(); \
CHECK_EXCEPTION; \
} \
- i = Double::toInt32(d); \
+ i = QJSNumberCoercion::toInteger(d); \
} \
} while (false)