"" + 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/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 5d756e3..17b7da0 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,25 @@
+2013-03-20 Filip Pizlo <fpizlo@apple.com>
+
+ "" + 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):
+
2013-03-20 Zoltan Herczeg <zherczeg@webkit.org>
ARMv7 replaceWithJump ASSERT failure after r135330.
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)
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index c32f846..a72e7ab 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -34,6 +34,17 @@
namespace JSC { namespace DFG {
+SpeculatedType resultOfToPrimitive(SpeculatedType type)
+{
+ if (type & SpecObject) {
+ // Objects get turned into strings. So if the input has hints of objectness,
+ // the output will have hinsts of stringiness.
+ return mergeSpeculations(type & ~SpecObject, SpecString);
+ }
+
+ return type;
+}
+
class PredictionPropagationPhase : public Phase {
public:
PredictionPropagationPhase(Graph& graph)
@@ -421,22 +432,8 @@
case ToPrimitive: {
SpeculatedType child = node->child1()->prediction();
- if (child) {
- if (isObjectSpeculation(child)) {
- // I'd love to fold this case into the case below, but I can't, because
- // removing SpecObject from something that only has an object
- // prediction and nothing else means we have an ill-formed SpeculatedType
- // (strong predict-none). This should be killed once we remove all traces
- // of static (aka weak) predictions.
- changed |= mergePrediction(SpecString);
- } else if (child & SpecObject) {
- // Objects get turned into strings. So if the input has hints of objectness,
- // the output will have hinsts of stringiness.
- changed |= mergePrediction(
- mergeSpeculations(child & ~SpecObject, SpecString));
- } else
- changed |= mergePrediction(child);
- }
+ if (child)
+ changed |= mergePrediction(resultOfToPrimitive(child));
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.h b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.h
index ae025cd..29fe845 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.h
@@ -30,6 +30,8 @@
#if ENABLE(DFG_JIT)
+#include "SpeculatedType.h"
+
namespace JSC { namespace DFG {
class Graph;
@@ -45,6 +47,9 @@
bool performPredictionPropagation(Graph&);
+// Helper used for FixupPhase for computing the predicted type of a ToPrimitive.
+SpeculatedType resultOfToPrimitive(SpeculatedType type);
+
} } // namespace JSC::DFG::Phase
#endif // ENABLE(DFG_JIT)