Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (97029 => 97030)
--- trunk/Source/_javascript_Core/ChangeLog 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-10-09 20:07:36 UTC (rev 97030)
@@ -1,3 +1,30 @@
+2011-10-09 Filip Pizlo <fpi...@apple.com>
+
+ DFG should not always speculate that a ByVal access has an integer index
+ https://bugs.webkit.org/show_bug.cgi?id=69716
+
+ Reviewed by Oliver Hunt.
+
+ 1% win on SunSpider, neutral elsewhere.
+
+ * dfg/DFGJITCodeGenerator.h:
+ (JSC::DFG::callOperation):
+ * dfg/DFGNode.h:
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPropagator.cpp:
+ (JSC::DFG::Propagator::byValHasIntBase):
+ (JSC::DFG::Propagator::clobbersWorld):
+ (JSC::DFG::Propagator::getMethodLoadElimination):
+ (JSC::DFG::Propagator::checkStructureLoadElimination):
+ (JSC::DFG::Propagator::getByOffsetLoadElimination):
+ (JSC::DFG::Propagator::getPropertyStorageLoadElimination):
+ (JSC::DFG::Propagator::performNodeCSE):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
2011-10-09 Yuqiang Xian <yuqiang.x...@intel.com>
Fix value profiling in 32_64 JIT
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-10-09 20:07:36 UTC (rev 97030)
@@ -1154,6 +1154,14 @@
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
+ void callOperation(J_DFGOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ setupStubArguments(arg1, arg2);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
{
setupStubArguments(arg1, arg2);
@@ -1173,6 +1181,13 @@
appendCallWithExceptionCheck(operation);
}
+ void callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ setupStubArguments(arg1, arg2, arg3);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ }
void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
{
setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
@@ -1328,6 +1343,16 @@
appendCallWithExceptionCheck(operation);
setupResults(resultTag, resultPayload);
}
+ void callOperation(J_DFGOperation_ECJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload)
+ {
+ m_jit.push(arg2Tag);
+ m_jit.push(arg2Payload);
+ m_jit.push(arg1);
+ m_jit.push(GPRInfo::callFrameRegister);
+
+ appendCallWithExceptionCheck(operation);
+ setupResults(resultTag, resultPayload);
+ }
void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, void* pointer)
{
m_jit.push(JITCompiler::TrustedImm32(reinterpret_cast<int>(pointer)));
@@ -1355,7 +1380,18 @@
appendCallWithExceptionCheck(operation);
}
+ void callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
+ {
+ m_jit.push(arg3Tag);
+ m_jit.push(arg3Payload);
+ m_jit.push(arg2Tag);
+ m_jit.push(arg2Payload);
+ m_jit.push(arg1);
+ m_jit.push(GPRInfo::callFrameRegister);
+ appendCallWithExceptionCheck(operation);
+ }
+
void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
{
m_jit.subPtr(TrustedImm32(2 * sizeof(double)), JITCompiler::stackPointerRegister);
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2011-10-09 20:07:36 UTC (rev 97030)
@@ -321,7 +321,7 @@
/* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\
/* Since a put to 'length' may invalidate optimizations here, */\
/* this must be the directly subsequent property put. */\
- macro(GetByVal, NodeResultJS | NodeMustGenerate) \
+ macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
macro(PutByVal, NodeMustGenerate | NodeClobbersWorld) \
macro(PutByValAlias, NodeMustGenerate | NodeClobbersWorld) \
macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-10-09 20:07:36 UTC (rev 97030)
@@ -263,6 +263,26 @@
return JSValue::encode(baseValue.get(exec, ident));
}
+EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
+{
+ JSValue property = JSValue::decode(encodedProperty);
+
+ if (property.isUInt32())
+ return getByVal(exec, base, property.asUInt32());
+ if (property.isDouble()) {
+ double propertyAsDouble = property.asDouble();
+ uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
+ if (propertyAsUInt32 == propertyAsDouble)
+ return getByVal(exec, base, propertyAsUInt32);
+ } else if (property.isString()) {
+ if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec)))
+ return JSValue::encode(result);
+ }
+
+ Identifier ident(exec, property.toString(exec));
+ return JSValue::encode(JSValue(base).get(exec, ident));
+}
+
EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
{
JSValue baseValue = JSValue::decode(encodedBase);
@@ -366,6 +386,16 @@
operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
}
+void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+ operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
+}
+
+void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+ operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
+}
+
void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
{
// We should only get here if index is outside the existing vector.
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-10-09 20:07:36 UTC (rev 97030)
@@ -54,6 +54,7 @@
typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EA)(ExecState*, JSArray*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
@@ -65,6 +66,7 @@
typedef RegisterSizedBoolean DFG_OPERATION (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef RegisterSizedBoolean DFG_OPERATION (*Z_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void DFG_OPERATION (*V_DFGOperation_ECJJ)(ExecState*, JSCell*, EncodedJSValue, EncodedJSValue);
typedef void DFG_OPERATION (*V_DFGOperation_EJJP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
typedef void DFG_OPERATION (*V_DFGOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*);
typedef double (*D_DFGOperation_DD)(double, double); // Using default calling conventions!
@@ -82,6 +84,7 @@
EncodedJSValue DFG_OPERATION operationArithDiv(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
EncodedJSValue DFG_OPERATION operationArithMod(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty);
+EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty);
EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue encodedBase, Identifier*);
EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*);
EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*);
@@ -100,6 +103,8 @@
void DFG_OPERATION operationThrowHasInstanceError(ExecState*, EncodedJSValue base);
void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*);
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*);
Modified: trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp 2011-10-09 20:07:36 UTC (rev 97030)
@@ -880,6 +880,12 @@
return isBooleanPrediction(prediction) || !prediction;
}
+ bool byValHasIntBase(Node& node)
+ {
+ PredictedType prediction = m_graph[node.child2()].prediction();
+ return (prediction & PredictInt32) || !prediction;
+ }
+
bool clobbersWorld(NodeIndex nodeIndex)
{
Node& node = m_graph[nodeIndex];
@@ -897,6 +903,8 @@
return !isPredictedNumerical(node);
case LogicalNot:
return !logicalNotIsPure(node);
+ case GetByVal:
+ return !byValHasIntBase(node);
default:
ASSERT_NOT_REACHED();
return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
@@ -1011,10 +1019,13 @@
case PutByVal:
case PutByValAlias:
- // PutByVal currently always speculates that it's accessing an array with an
- // integer index, which means that it's impossible for it to cause a structure
- // change.
- break;
+ if (byValHasIntBase(node)) {
+ // If PutByVal speculates that it's accessing an array with an
+ // integer index, then it's impossible for it to cause a structure
+ // change.
+ break;
+ }
+ return NoNode;
case ArrayPush:
case ArrayPop:
@@ -1076,10 +1087,13 @@
case PutByVal:
case PutByValAlias:
- // PutByVal currently always speculates that it's accessing an array with an
- // integer index, which means that it's impossible for it to cause a structure
- // change.
- break;
+ if (byValHasIntBase(node)) {
+ // If PutByVal speculates that it's accessing an array with an
+ // integer index, then it's impossible for it to cause a structure
+ // change.
+ break;
+ }
+ return false;
default:
if (clobbersWorld(index))
@@ -1116,10 +1130,13 @@
case PutByVal:
case PutByValAlias:
- // PutByVal currently always speculates that it's accessing an array with an
- // integer index, which means that it's impossible for it to cause a structure
- // change.
- break;
+ if (byValHasIntBase(node)) {
+ // If PutByVal speculates that it's accessing an array with an
+ // integer index, then it's impossible for it to cause a structure
+ // change.
+ break;
+ }
+ return NoNode;
default:
if (clobbersWorld(index))
@@ -1149,10 +1166,13 @@
case PutByVal:
case PutByValAlias:
- // PutByVal currently always speculates that it's accessing an array with an
- // integer index, which means that it's impossible for it to cause a structure
- // change.
- break;
+ if (byValHasIntBase(node)) {
+ // If PutByVal speculates that it's accessing an array with an
+ // integer index, then it's impossible for it to cause a structure
+ // change.
+ break;
+ }
+ return NoNode;
default:
if (clobbersWorld(index))
@@ -1321,11 +1341,12 @@
break;
case GetByVal:
- setReplacement(getByValLoadElimination(node.child1(), node.child2()));
+ if (byValHasIntBase(node))
+ setReplacement(getByValLoadElimination(node.child1(), node.child2()));
break;
case PutByVal:
- if (getByValLoadElimination(node.child1(), node.child2()) != NoNode)
+ if (byValHasIntBase(node) && getByValLoadElimination(node.child1(), node.child2()) != NoNode)
node.op = PutByValAlias;
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2011-10-09 20:07:36 UTC (rev 97030)
@@ -1272,6 +1272,23 @@
}
case GetByVal: {
+ PredictedType basePrediction = at(node.child2()).prediction();
+ if (!(basePrediction & PredictInt32) && basePrediction) {
+ SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
+ JSValueOperand property(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyTagGPR = property.tagGPR();
+ GPRReg propertyPayloadGPR = property.payloadGPR();
+
+ flushRegisters();
+ GPRResult2 resultTag(this);
+ GPRResult resultPayload(this);
+ callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
+
+ jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
+ break;
+ }
+
if (at(node.child1()).prediction() == PredictString) {
compileGetByValOnString(node);
if (!m_compileOkay)
@@ -1314,6 +1331,24 @@
}
case PutByVal: {
+ PredictedType basePrediction = at(node.child2()).prediction();
+ if (!(basePrediction & PredictInt32) && basePrediction) {
+ 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());
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyTagGPR = property.tagGPR();
+ GPRReg propertyPayloadGPR = property.payloadGPR();
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
+
+ flushRegisters();
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
JSValueOperand value(this, node.child3());
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (97029 => 97030)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2011-10-09 20:07:36 UTC (rev 97030)
@@ -1383,6 +1383,21 @@
}
case GetByVal: {
+ PredictedType basePrediction = at(node.child2()).prediction();
+ if (!(basePrediction & PredictInt32) && basePrediction) {
+ JSValueOperand base(this, node.child1());
+ JSValueOperand property(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyGPR = property.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationGetByVal, result.gpr(), baseGPR, propertyGPR);
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
if (at(node.child1()).prediction() == PredictString) {
compileGetByValOnString(node);
if (!m_compileOkay)
@@ -1424,6 +1439,22 @@
}
case PutByVal: {
+ PredictedType basePrediction = at(node.child2()).prediction();
+ if (!(basePrediction & PredictInt32) && basePrediction) {
+ JSValueOperand arg1(this, node.child1());
+ JSValueOperand arg2(this, node.child2());
+ JSValueOperand arg3(this, node.child3());
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ GPRReg arg3GPR = arg3.gpr();
+ flushRegisters();
+
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
JSValueOperand value(this, node.child3());
@@ -1488,6 +1519,9 @@
}
case PutByValAlias: {
+ PredictedType basePrediction = at(node.child2()).prediction();
+ ASSERT_UNUSED(basePrediction, (basePrediction & PredictInt32) || !basePrediction);
+
SpeculateCellOperand base(this, node.child1());
SpeculateStrictInt32Operand property(this, node.child2());
JSValueOperand value(this, node.child3());