various math operations don't properly check for an exception after calling toNumber() on the lhs
https://bugs.webkit.org/show_bug.cgi?id=160154

Reviewed by Mark Lam.

JSTests:

* stress/to-number-throws-correct-exception.js: Added.
(test.let.test.runTest.):
(test.let.test.runTest.get f):
(test.let.test.runTest):
(test.let.test):
(test):
(test2.runTest.):
(test2.runTest.get f):
(test2.runTest):
(test2):

Source/JavaScriptCore:

We must check for an exception after calling toNumber() on the lhs
because this can throw an exception. If we called toNumber() on
the rhs without first checking for an exception after the toNumber()
on the lhs, this can lead us to execute effectful code or deviate
from the standard in subtle ways. I fixed this bug in various places
by always checking for an exception after calling toNumber() on the
lhs for the various bit and arithmetic operations.

This patch also found a commutativity bug inside DFGStrengthReduction.
We could end up commuting the lhs and rhs of say an "|" expression
even when the lhs/rhs may not be numbers. This is wrong because
executing toNumber() on the lhs/rhs has strict ordering guarantees
by the specification and is observable by user programs.

* dfg/DFGOperations.cpp:
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleCommutativity):
* jit/JITOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/Operations.cpp:
(JSC::jsAddSlowCase):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@204206 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
index 586bd96..2b2ea9e 100644
--- a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
@@ -744,13 +744,18 @@
     
     void handleCommutativity()
     {
+        // It's definitely not sound to swap the lhs and rhs when we may be performing effectful
+        // calls on the lhs/rhs for valueOf.
+        if (m_node->child1().useKind() == UntypedUse || m_node->child2().useKind() == UntypedUse)
+            return;
+
         // If the right side is a constant then there is nothing left to do.
         if (m_node->child2()->hasConstant())
             return;
         
         // This case ensures that optimizations that look for x + const don't also have
         // to look for const + x.
-        if (m_node->child1()->hasConstant()) {
+        if (m_node->child1()->hasConstant() && !m_node->child1()->asJSValue().isCell()) {
             std::swap(m_node->child1(), m_node->child2());
             m_changed = true;
             return;