aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@qt.io>2019-03-18 11:49:05 +0100
committerErik Verbruggen <erik.verbruggen@qt.io>2019-03-21 08:52:54 +0000
commitc091f3f4b4889ac6be26e018c5e8b673adee7c47 (patch)
tree9b7090f13245248955deff6cb35243c814576c32
parent3af36ba6eb58b2f455e015579540baa51e0c5c26 (diff)
V4: Do not invert non-reflexive comparison binops
This is only useful for the few (4) comparisons where we have specialized instructions, and it's very error-prone. Change-Id: I37efe94f54ba0adf393d9236df2d13aa6685eb46 Fixes: QTBUG-74476 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qv4codegen.cpp85
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp10
2 files changed, 46 insertions, 49 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b0bec5b6f2..3fdba08f20 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1738,59 +1738,46 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
return Reference::fromAccumulator(this);
}
-static QSOperator::Op operatorForSwappedOperands(QSOperator::Op oper)
-{
- switch (oper) {
- case QSOperator::StrictEqual: return QSOperator::StrictEqual;
- case QSOperator::StrictNotEqual: return QSOperator::StrictNotEqual;
- case QSOperator::Equal: return QSOperator::Equal;
- case QSOperator::NotEqual: return QSOperator::NotEqual;
- case QSOperator::Gt: return QSOperator::Le;
- case QSOperator::Ge: return QSOperator::Lt;
- case QSOperator::Lt: return QSOperator::Ge;
- case QSOperator::Le: return QSOperator::Gt;
- default: Q_UNIMPLEMENTED(); return QSOperator::Invalid;
- }
-}
-
Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right)
{
- if (left.isConstant()) {
- oper = operatorForSwappedOperands(oper);
- qSwap(left, right);
- }
+ // See if we can generate specialized comparison instructions:
+ if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) {
+ // Because == and != are reflexive, we can do the following:
+ if (left.isConstant() && !right.isConstant())
+ qSwap(left, right); // null==a -> a==null
- if (right.isConstant() && (oper == QSOperator::Equal || oper == QSOperator::NotEqual)) {
- Value c = Value::fromReturnedValue(right.constant);
- if (c.isNull() || c.isUndefined()) {
- left.loadInAccumulator();
- if (oper == QSOperator::Equal) {
- Instruction::CmpEqNull cmp;
- bytecodeGenerator->addInstruction(cmp);
- addCJump();
- return Reference();
- } else if (oper == QSOperator::NotEqual) {
- Instruction::CmpNeNull cmp;
- bytecodeGenerator->addInstruction(cmp);
- addCJump();
- return Reference();
- }
- } else if (c.isInt32()) {
- left.loadInAccumulator();
- if (oper == QSOperator::Equal) {
- Instruction::CmpEqInt cmp;
- cmp.lhs = c.int_32();
- bytecodeGenerator->addInstruction(cmp);
- addCJump();
- return Reference();
- } else if (oper == QSOperator::NotEqual) {
- Instruction::CmpNeInt cmp;
- cmp.lhs = c.int_32();
- bytecodeGenerator->addInstruction(cmp);
- addCJump();
- return Reference();
- }
+ if (right.isConstant()) {
+ Value c = Value::fromReturnedValue(right.constant);
+ if (c.isNull() || c.isUndefined()) {
+ left.loadInAccumulator();
+ if (oper == QSOperator::Equal) {
+ Instruction::CmpEqNull cmp;
+ bytecodeGenerator->addInstruction(cmp);
+ addCJump();
+ return Reference();
+ } else if (oper == QSOperator::NotEqual) {
+ Instruction::CmpNeNull cmp;
+ bytecodeGenerator->addInstruction(cmp);
+ addCJump();
+ return Reference();
+ }
+ } else if (c.isInt32()) {
+ left.loadInAccumulator();
+ if (oper == QSOperator::Equal) {
+ Instruction::CmpEqInt cmp;
+ cmp.lhs = c.int_32();
+ bytecodeGenerator->addInstruction(cmp);
+ addCJump();
+ return Reference();
+ } else if (oper == QSOperator::NotEqual) {
+ Instruction::CmpNeInt cmp;
+ cmp.lhs = c.int_32();
+ bytecodeGenerator->addInstruction(cmp);
+ addCJump();
+ return Reference();
+ }
+ }
}
}
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 42d8f37ca8..0491ccd473 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -235,6 +235,8 @@ private slots:
void importModuleWithLexicallyScopedVars();
void importExportErrors();
+ void equality();
+
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
Q_INVOKABLE void throwingCppMethod2();
@@ -4622,6 +4624,14 @@ void tst_QJSEngine::importExportErrors()
}
}
+void tst_QJSEngine::equality()
+{
+ QJSEngine engine;
+ QJSValue ok = engine.evaluate("(0 < 0) ? 'ko' : 'ok'");
+ QVERIFY(ok.isString());
+ QCOMPARE(ok.toString(), QString("ok"));
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"