ValueAdd should be constant folded if the operands are constant String,Primitive or Primitive,String
https://bugs.webkit.org/show_bug.cgi?id=163182

Reviewed by Filip Pizlo.

JSTests:

* microbenchmarks/string-add-constant-folding.js: Added.
(assert):
(runTests):
(add):
(test):

Source/JavaScriptCore:

This code pattern shows up in Dromaeo, so it's worth optimizing for.
This might also show up in real world JS code due to inlining and other
types of constant folding.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGLazyJSValue.cpp:
(JSC::DFG::LazyJSValue::getValue):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@207060 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
index bfd7849..c8b3ff8 100644
--- a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
@@ -322,8 +322,48 @@
         // move these to the abstract interpreter once AbstractValue can support LazyJSValue.
         // https://bugs.webkit.org/show_bug.cgi?id=155204
 
+        case ValueAdd: {
+            if (m_node->child1()->isConstant()
+                && m_node->child2()->isConstant()
+                && (!!m_node->child1()->tryGetString(m_graph) || !!m_node->child2()->tryGetString(m_graph))) {
+                auto tryGetConstantString = [&] (Node* node) -> String {
+                    String string = node->tryGetString(m_graph);
+                    if (!string.isEmpty())
+                        return string;
+                    JSValue value = node->constant()->value();
+                    if (!value)
+                        return String();
+                    if (value.isInt32())
+                        return String::number(value.asInt32());
+                    if (value.isNumber())
+                        return String::numberToStringECMAScript(value.asNumber());
+                    if (value.isBoolean())
+                        return value.asBoolean() ? ASCIILiteral("true") : ASCIILiteral("false");
+                    if (value.isNull())
+                        return ASCIILiteral("null");
+                    if (value.isUndefined())
+                        return ASCIILiteral("undefined");
+                    return String();
+                };
+
+                String leftString = tryGetConstantString(m_node->child1().node());
+                if (!leftString)
+                    break;
+                String rightString = tryGetConstantString(m_node->child2().node());
+                if (!rightString)
+                    break;
+
+                StringBuilder builder;
+                builder.append(leftString);
+                builder.append(rightString);
+                m_node->convertToLazyJSConstant(
+                    m_graph, LazyJSValue::newString(m_graph, builder.toString()));
+                m_changed = true;
+            }
+            break;
+        }
+
         case MakeRope:
-        case ValueAdd:
         case StrCat: {
             String leftString = m_node->child1()->tryGetString(m_graph);
             if (!leftString)