"" + x where x is not a string should be optimized by the DFG to some manner of ToString conversion
https://bugs.webkit.org/show_bug.cgi?id=112845
Reviewed by Mark Hahnenberg.
I like to do "" + x. So I decided to make DFG recognize it, and related idioms.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupToPrimitive):
(FixupPhase):
(JSC::DFG::FixupPhase::fixupToString):
(JSC::DFG::FixupPhase::attemptToMakeFastStringAdd):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::resultOfToPrimitive):
(DFG):
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPredictionPropagationPhase.h:
(DFG):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@146400 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 30318f3..4debbac 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -31,6 +31,7 @@
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
+#include "DFGPredictionPropagationPhase.h"
#include "DFGVariableAccessDataDump.h"
#include "Operations.h"
@@ -555,61 +556,12 @@
}
case ToPrimitive: {
- if (node->child1()->shouldSpeculateInteger()) {
- setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
- node->convertToIdentity();
- break;
- }
-
- if (node->child1()->shouldSpeculateString()) {
- setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
- node->convertToIdentity();
- break;
- }
-
- if (node->child1()->shouldSpeculateStringObject()
- && canOptimizeStringObjectAccess(node->codeOrigin)) {
- setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
- node->convertToToString();
- break;
- }
-
- if (node->child1()->shouldSpeculateStringOrStringObject()
- && canOptimizeStringObjectAccess(node->codeOrigin)) {
- setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
- node->convertToToString();
- break;
- }
-
- // FIXME: Add string speculation here.
- // https://bugs.webkit.org/show_bug.cgi?id=110175
+ fixupToPrimitive(node);
break;
}
case ToString: {
- if (node->child1()->shouldSpeculateString()) {
- setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
- node->convertToIdentity();
- break;
- }
-
- if (node->child1()->shouldSpeculateStringObject()
- && canOptimizeStringObjectAccess(node->codeOrigin)) {
- setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
- break;
- }
-
- if (node->child1()->shouldSpeculateStringOrStringObject()
- && canOptimizeStringObjectAccess(node->codeOrigin)) {
- setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
- break;
- }
-
- if (node->child1()->shouldSpeculateCell()) {
- setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
- break;
- }
-
+ fixupToString(node);
break;
}
@@ -981,6 +933,61 @@
}
}
+ void fixupToPrimitive(Node* node)
+ {
+ if (node->child1()->shouldSpeculateInteger()) {
+ setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+ node->convertToIdentity();
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateString()) {
+ setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+ node->convertToIdentity();
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+ node->convertToToString();
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateStringOrStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+ node->convertToToString();
+ return;
+ }
+ }
+
+ void fixupToString(Node* node)
+ {
+ if (node->child1()->shouldSpeculateString()) {
+ setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+ node->convertToIdentity();
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateStringOrStringObject()
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
+ setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+ return;
+ }
+
+ if (node->child1()->shouldSpeculateCell()) {
+ setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+ return;
+ }
+ }
+
template<UseKind leftUseKind>
bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right)
{
@@ -989,32 +996,37 @@
if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->codeOrigin))
return false;
- if (right->shouldSpeculateString()) {
- convertStringAddUse<leftUseKind>(node, left);
+ convertStringAddUse<leftUseKind>(node, left);
+
+ if (right->shouldSpeculateString())
convertStringAddUse<StringUse>(node, right);
- convertToMakeRope(node);
- return true;
- }
-
- if (right->shouldSpeculateStringObject()
- && canOptimizeStringObjectAccess(node->codeOrigin)) {
- convertStringAddUse<leftUseKind>(node, left);
+ else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
convertStringAddUse<StringObjectUse>(node, right);
- convertToMakeRope(node);
- return true;
- }
-
- if (right->shouldSpeculateStringOrStringObject()
- && canOptimizeStringObjectAccess(node->codeOrigin)) {
- convertStringAddUse<leftUseKind>(node, left);
+ else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
convertStringAddUse<StringOrStringObjectUse>(node, right);
- convertToMakeRope(node);
- return true;
+ else {
+ // At this point we know that the other operand is something weird. The semantically correct
+ // way of dealing with this is:
+ //
+ // MakeRope(@left, ToString(ToPrimitive(@right)))
+ //
+ // So that's what we emit. NB, we need to do all relevant type checks on @left before we do
+ // anything to @right, since ToPrimitive may be effectful.
+
+ Node* toPrimitive = m_insertionSet.insertNode(
+ m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive, node->codeOrigin,
+ Edge(right.node()));
+ Node* toString = m_insertionSet.insertNode(
+ m_indexInBlock, SpecString, ToString, node->codeOrigin, Edge(toPrimitive));
+
+ fixupToPrimitive(toPrimitive);
+ fixupToString(toString);
+
+ right.setNode(toString);
}
- // FIXME: We ought to be able to convert the right case to do
- // ToPrimitiveToString.
- return false; // Let the slow path worry about it.
+ convertToMakeRope(node);
+ return true;
}
bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, const Identifier& ident)