aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-08-20 16:42:11 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-22 00:20:59 +0200
commite75a96a920fb867fbe698e1aeb5a292a0ea35b8b (patch)
treed44f5ccb8dacdcc4f461c64d59bd5c5ec436feaa /src/qml/qml
parentbc6456d722e7a23f145baf13b8d1c15f81513aad (diff)
Fix V4 calculations that vary from V8 results
Task-number: QTBUG-24706 Change-Id: I4475a772c5cd92776f2cb73dab9bc06ae4c019fa Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp107
-rw-r--r--src/qml/qml/v4/qv4program_p.h1
2 files changed, 100 insertions, 8 deletions
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index fb484546a2..6dce2782c6 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -84,13 +84,64 @@ QQmlAbstractBinding::VTable QV4Bindings_Binding_vtable = {
};
namespace {
+
+// The highest bit is the sign bit, in any endianness
+static const quint64 doubleSignMask = (quint64(0x1) << 63);
+
+inline bool signBitSet(const double &v)
+{
+ union { double d; quint64 u; } u;
+ u.d = v;
+ return (u.u & doubleSignMask);
+}
+
+inline double setSignBit(const double &v, bool b = true)
+{
+ union { double d; quint64 u; } u;
+
+ u.d = v;
+ if (b) {
+ u.u |= doubleSignMask;
+ } else {
+ u.u &= ~doubleSignMask;
+ }
+ return u.d;
+}
+
+inline double clearSignBit(const double &v, bool b = true)
+{
+ return setSignBit(v, !b);
+}
+
struct Register {
typedef QQmlRegisterType Type;
+ enum SpecialNumericValue {
+ NegativeZero = 1,
+ PositiveInfinity = 2,
+ NegativeInfinity = 3,
+ NotANumber = 4
+ };
+
inline void setUndefined() { dataType = UndefinedType; }
+ inline bool isUndefined() const { return dataType == UndefinedType; }
+
inline void setNull() { dataType = NullType; }
+
inline void setNaN() { setnumber(qSNaN()); }
- inline bool isUndefined() const { return dataType == UndefinedType; }
+ inline void setNaNType() { dataType = SpecialNumericType; intValue = NotANumber; } // non-numeric representation of NaN
+ inline bool isNaN() const { return (((dataType == SpecialNumericType) && (intValue == NotANumber)) ||
+ ((dataType == NumberType) && qIsNaN(numberValue))); }
+
+ inline void setInf(bool negative) { setnumber(setSignBit(qInf(), negative)); }
+ inline void setInfType(bool negative) { dataType = SpecialNumericType; intValue = (negative ? NegativeInfinity : PositiveInfinity); } // non-numeric representation of Inf
+ inline bool isInf() const { return (((dataType == SpecialNumericType) && ((intValue == NegativeInfinity) || (intValue == PositiveInfinity))) ||
+ ((dataType == NumberType) && qIsInf(numberValue))); }
+
+ inline void setNegativeZero() { setnumber(setSignBit(0)); }
+ inline void setNegativeZeroType() { dataType = SpecialNumericType; intValue = NegativeZero; } // non-numeric representation of -0
+ inline bool isNegativeZero() const { return (((dataType == SpecialNumericType) && (intValue == NegativeZero)) ||
+ ((dataType == NumberType) && (numberValue == 0) && signBitSet(numberValue))); }
inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
inline QObject *getQObject() const { return qobjectValue; }
@@ -1104,6 +1155,9 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
+ else if (src.isNaN()) output.setNaN();
+ else if (src.isInf()) output.setInf(src.getint() == Register::NegativeInfinity);
+ else if (src.isNegativeZero()) output.setNegativeZero();
else output.setnumber(double(src.getint()));
}
QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
@@ -1734,7 +1788,7 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setnumber(qAbs(src.getnumber()));
+ else output.setnumber(clearSignBit(qAbs(src.getnumber())));
}
QML_V4_END_INSTR(MathAbsNumber, unaryop)
@@ -1760,8 +1814,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setint(qCeil(src.getnumber()));
+ if (src.isUndefined())
+ output.setUndefined();
+ else if (src.isNaN())
+ // output should be an int, but still NaN
+ output.setNaNType();
+ else if (src.isInf())
+ // output should be an int, but still Inf
+ output.setInfType(signBitSet(src.getnumber()));
+ else if (src.isNegativeZero())
+ // output should be an int, but still -0
+ output.setNegativeZeroType();
+ else
+ output.setint(qCeil(src.getnumber()));
}
QML_V4_END_INSTR(MathCeilNumber, unaryop)
@@ -2101,8 +2166,21 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
const Register &left = registers[instr->binaryop.left];
const Register &right = registers[instr->binaryop.right];
Register &output = registers[instr->binaryop.output];
- if (left.isUndefined() || right.isUndefined()) output.setUndefined();
- else output.setnumber(qMax(left.getnumber(), right.getnumber()));
+ if (left.isUndefined() || right.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const double lhs = left.getnumber();
+ const double rhs = right.getnumber();
+ double result(lhs);
+ if (lhs == rhs) {
+ // If these are both zero, +0 is greater than -0
+ if (signBitSet(lhs) && !signBitSet(rhs))
+ result = rhs;
+ } else {
+ result = qMax(lhs, rhs);
+ }
+ output.setnumber(result);
+ }
}
QML_V4_END_INSTR(MathMaxNumber, binaryop)
@@ -2111,8 +2189,21 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
const Register &left = registers[instr->binaryop.left];
const Register &right = registers[instr->binaryop.right];
Register &output = registers[instr->binaryop.output];
- if (left.isUndefined() || right.isUndefined()) output.setUndefined();
- else output.setnumber(qMin(left.getnumber(), right.getnumber()));
+ if (left.isUndefined() || right.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const double lhs = left.getnumber();
+ const double rhs = right.getnumber();
+ double result(lhs);
+ if (lhs == rhs) {
+ // If these are both zero, -0 is lesser than +0
+ if (!signBitSet(lhs) && signBitSet(rhs))
+ result = rhs;
+ } else {
+ result = qMin(lhs, rhs);
+ }
+ output.setnumber(result);
+ }
}
QML_V4_END_INSTR(MathMinNumber, binaryop)
diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h
index d859a83abb..6d932d9d99 100644
--- a/src/qml/qml/v4/qv4program_p.h
+++ b/src/qml/qml/v4/qv4program_p.h
@@ -95,6 +95,7 @@ enum QQmlRegisterType {
FloatType,
IntType,
BoolType,
+ SpecialNumericType,
PODValueType,