https://bugs.webkit.org/show_bug.cgi?id=75160
<rdar://problem/
10622646>
<rdar://problem/
10622649>
Reviewed by Oliver Hunt.
Added the ability to call slow path when the base is known to not be an array.
Also rationalized the logic for deciding when the index is not an int, and
cleaned up the logic for deciding when to speculate typed array.
Neutral for the most part, with odd speed-ups and slow-downs. The slow-downs can
likely be mitigated by having the notion of a polymorphic array access, where we
try, but don't speculate, to access the array one way before either trying some
other ways or calling slow path.
* bytecode/PredictedType.h:
(JSC::isActionableMutableArrayPrediction):
(JSC::isActionableArrayPrediction):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateInt8Array):
(JSC::DFG::Node::shouldSpeculateInt16Array):
(JSC::DFG::Node::shouldSpeculateInt32Array):
(JSC::DFG::Node::shouldSpeculateUint8Array):
(JSC::DFG::Node::shouldSpeculateUint16Array):
(JSC::DFG::Node::shouldSpeculateUint32Array):
(JSC::DFG::Node::shouldSpeculateFloat32Array):
(JSC::DFG::Node::shouldSpeculateFloat64Array):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::byValIsPure):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@103604
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-12-22 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should not speculate array even when predictions say that the base is not an array
+ https://bugs.webkit.org/show_bug.cgi?id=75160
+ <rdar://problem/10622646>
+ <rdar://problem/10622649>
+
+ Reviewed by Oliver Hunt.
+
+ Added the ability to call slow path when the base is known to not be an array.
+ Also rationalized the logic for deciding when the index is not an int, and
+ cleaned up the logic for deciding when to speculate typed array.
+
+ Neutral for the most part, with odd speed-ups and slow-downs. The slow-downs can
+ likely be mitigated by having the notion of a polymorphic array access, where we
+ try, but don't speculate, to access the array one way before either trying some
+ other ways or calling slow path.
+
+ * bytecode/PredictedType.h:
+ (JSC::isActionableMutableArrayPrediction):
+ (JSC::isActionableArrayPrediction):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::shouldSpeculateInt8Array):
+ (JSC::DFG::Node::shouldSpeculateInt16Array):
+ (JSC::DFG::Node::shouldSpeculateInt32Array):
+ (JSC::DFG::Node::shouldSpeculateUint8Array):
+ (JSC::DFG::Node::shouldSpeculateUint16Array):
+ (JSC::DFG::Node::shouldSpeculateUint32Array):
+ (JSC::DFG::Node::shouldSpeculateFloat32Array):
+ (JSC::DFG::Node::shouldSpeculateFloat64Array):
+ * dfg/DFGPropagator.cpp:
+ (JSC::DFG::Propagator::byValIsPure):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
2011-12-22 Gavin Barraclough <barraclough@apple.com>
Unreviewed - fix stylebot issues from last patch.
return value == PredictFloat64Array;
}
+inline bool isActionableMutableArrayPrediction(PredictedType value)
+{
+ return isArrayPrediction(value)
+ || isByteArrayPrediction(value)
+ || isInt8ArrayPrediction(value)
+ || isInt16ArrayPrediction(value)
+ || isInt32ArrayPrediction(value)
+ || isUint8ArrayPrediction(value)
+ || isUint16ArrayPrediction(value)
+ || isUint32ArrayPrediction(value)
+#if CPU(X86) || CPU(X86_64)
+ || isFloat32ArrayPrediction(value)
+#endif
+ || isFloat64ArrayPrediction(value);
+}
+
+inline bool isActionableArrayPrediction(PredictedType value)
+{
+ return isStringPrediction(value)
+ || isActionableMutableArrayPrediction(value);
+}
+
inline bool isArrayOrOtherPrediction(PredictedType value)
{
return !!(value & (PredictArray | PredictOther)) && !(value & ~(PredictArray | PredictOther));
break;
case GetByVal: {
- PredictedType indexPrediction = m_graph[node.child2()].prediction();
- if (!(indexPrediction & PredictInt32) && indexPrediction) {
+ if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) {
+ m_isValid = false;
+ break;
+ }
+ if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
clobberStructures(nodeIndex);
forNode(nodeIndex).makeTop();
break;
forNode(nodeIndex).set(PredictDouble);
break;
}
+ ASSERT(m_graph[node.child1()].shouldSpeculateArray());
forNode(node.child1()).filter(PredictArray);
forNode(node.child2()).filter(PredictInt32);
forNode(nodeIndex).makeTop();
case PutByVal:
case PutByValAlias: {
- PredictedType indexPrediction = m_graph[node.child2()].prediction();
- if (!(indexPrediction & PredictInt32) && indexPrediction) {
+ if (!m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) {
+ m_isValid = false;
+ break;
+ }
+ if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArrayPrediction(m_graph[node.child1()].prediction())) {
+ ASSERT(node.op == PutByVal);
clobberStructures(nodeIndex);
forNode(nodeIndex).makeTop();
break;
forNode(node.child3()).filter(PredictNumber);
break;
}
-
+ ASSERT(m_graph[node.child1()].shouldSpeculateArray());
forNode(node.child1()).filter(PredictArray);
forNode(node.child2()).filter(PredictInt32);
break;
bool shouldSpeculateInt8Array()
{
- return prediction() == PredictInt8Array;
+ return isInt8ArrayPrediction(prediction());
}
bool shouldSpeculateInt16Array()
{
- return prediction() == PredictInt16Array;
+ return isInt16ArrayPrediction(prediction());
}
bool shouldSpeculateInt32Array()
{
- return prediction() == PredictInt32Array;
+ return isInt32ArrayPrediction(prediction());
}
bool shouldSpeculateUint8Array()
{
- return prediction() == PredictUint8Array;
+ return isUint8ArrayPrediction(prediction());
}
bool shouldSpeculateUint16Array()
{
- return prediction() == PredictUint16Array;
+ return isUint16ArrayPrediction(prediction());
}
bool shouldSpeculateUint32Array()
{
- return prediction() == PredictUint32Array;
+ return isUint32ArrayPrediction(prediction());
}
bool shouldSpeculateFloat32Array()
{
#if CPU(X86) || CPU(X86_64)
- return !!(prediction() & PredictFloat32Array);
+ return isFloat32ArrayPrediction(prediction());
#else
return false;
#endif
bool shouldSpeculateFloat64Array()
{
- return prediction() == PredictFloat64Array;
+ return isFloat64ArrayPrediction(prediction());
}
bool shouldSpeculateArrayOrOther()
bool byValIsPure(Node& node)
{
- PredictedType prediction = m_graph[node.child2()].prediction();
- return (prediction & PredictInt32) || !prediction;
+ return m_graph[node.child2()].shouldSpeculateInteger()
+ && ((node.op == PutByVal || node.op == PutByValAlias)
+ ? isActionableMutableArrayPrediction(m_graph[node.child1()].prediction())
+ : isActionableArrayPrediction(m_graph[node.child1()].prediction()));
}
bool clobbersWorld(NodeIndex nodeIndex)
void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
{
+ if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ return;
+ }
+
SpeculateCellOperand base(this, node.child1());
GPRReg baseReg = base.gpr();
}
case GetByVal: {
- PredictedType basePrediction = at(node.child2()).prediction();
- if (!(basePrediction & PredictInt32) && basePrediction) {
+ if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ break;
+ }
+
+ if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) {
SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
JSValueOperand property(this, node.child2());
GPRReg baseGPR = base.gpr();
return;
break;
}
+
+ ASSERT(at(node.child1()).shouldSpeculateArray());
SpeculateStrictInt32Operand property(this, node.child2());
StorageOperand storage(this, node.child3());
}
case PutByVal: {
- PredictedType basePrediction = at(node.child2()).prediction();
- if (!(basePrediction & PredictInt32) && basePrediction) {
+ if (!at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ break;
+ }
+
+ if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArrayPrediction(at(node.child1()).prediction())) {
SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
JSValueOperand property(this, node.child2());
JSValueOperand value(this, node.child3());
return;
break;
}
+
+ ASSERT(at(node.child1()).shouldSpeculateArray());
JSValueOperand value(this, node.child3());
GPRTemporary scratch(this);
}
case PutByValAlias: {
+ if (!at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ break;
+ }
+
+ ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction()));
+ ASSERT(at(node.child2()).shouldSpeculateInteger());
+
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
break;
}
+ ASSERT(at(node.child1()).shouldSpeculateArray());
+
JSValueOperand value(this, node.child3());
GPRTemporary scratch(this, base);
}
case GetByVal: {
- PredictedType basePrediction = at(node.child2()).prediction();
- if (!(basePrediction & PredictInt32) && basePrediction) {
+ if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ break;
+ }
+
+ if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) {
JSValueOperand base(this, node.child1());
JSValueOperand property(this, node.child2());
GPRReg baseGPR = base.gpr();
return;
break;
}
+
+ ASSERT(at(node.child1()).shouldSpeculateArray());
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
}
case PutByVal: {
- PredictedType basePrediction = at(node.child2()).prediction();
- if (!(basePrediction & PredictInt32) && basePrediction) {
+ if (!at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ break;
+ }
+
+ if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArrayPrediction(at(node.child1()).prediction())) {
JSValueOperand arg1(this, node.child1());
JSValueOperand arg2(this, node.child2());
JSValueOperand arg3(this, node.child3());
return;
break;
}
+
+ ASSERT(at(node.child1()).shouldSpeculateArray());
JSValueOperand value(this, node.child3());
GPRTemporary scratch(this);
}
case PutByValAlias: {
- PredictedType basePrediction = at(node.child2()).prediction();
- ASSERT_UNUSED(basePrediction, (basePrediction & PredictInt32) || !basePrediction);
+ if (!at(node.child1()).prediction() || !at(node.child2()).prediction()) {
+ terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
+ break;
+ }
+
+ ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction()));
+ ASSERT(at(node.child2()).shouldSpeculateInteger());
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
return;
break;
}
+
+ ASSERT(at(node.child1()).shouldSpeculateArray());
JSValueOperand value(this, node.child3());
GPRTemporary scratch(this);