Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (124397 => 124398)
--- trunk/Source/_javascript_Core/ChangeLog 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-08-02 01:28:10 UTC (rev 124398)
@@ -1,3 +1,42 @@
+2012-08-01 Filip Pizlo <fpi...@apple.com>
+
+ DFG should distinguish between PutByVal's that clobber the world and ones that don't
+ https://bugs.webkit.org/show_bug.cgi?id=92923
+
+ Reviewed by Mark Hahnenberg.
+
+ This is performance-neutral. I also confirmed that it's neutral if we make the
+ clobbering variant (PutByValSafe) clobber all knowledge of what is an array,
+ which should feed nicely into work on removing uses of ClassInfo.
+
+ * bytecode/DFGExitProfile.h:
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::getByValLoadElimination):
+ (JSC::DFG::CSEPhase::checkStructureLoadElimination):
+ (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
+ (JSC::DFG::CSEPhase::getByOffsetLoadElimination):
+ (JSC::DFG::CSEPhase::putByOffsetStoreElimination):
+ (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
+ (JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination):
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::byValIsPure):
+ (JSC::DFG::Graph::clobbersWorld):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
2012-08-01 Jian Li <jia...@chromium.org>
Add new CSS property "-webkit-widget-region" to expose dashboard region support for other port
Modified: trunk/Source/_javascript_Core/bytecode/DFGExitProfile.h (124397 => 124398)
--- trunk/Source/_javascript_Core/bytecode/DFGExitProfile.h 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/bytecode/DFGExitProfile.h 2012-08-02 01:28:10 UTC (rev 124398)
@@ -38,6 +38,7 @@
BadCache, // We exited because an inline cache was wrong.
Overflow, // We exited because of overflow.
NegativeZero, // We exited because we encountered negative zero.
+ OutOfBounds, // We had an out-of-bounds access to an array.
InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -950,7 +950,8 @@
}
case PutByVal:
- case PutByValAlias: {
+ case PutByValAlias:
+ case PutByValSafe: {
node.setCanExit(true);
Edge child1 = m_graph.varArgChild(node, 0);
@@ -966,7 +967,7 @@
|| m_graph[child1].shouldSpeculateArguments()
#endif
) {
- ASSERT(node.op() == PutByVal);
+ ASSERT(node.op() == PutByVal || node.op() == PutByValSafe);
clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -1055,7 +1056,7 @@
ASSERT(m_graph[child1].shouldSpeculateArray());
forNode(child1).filter(SpecArray);
forNode(child2).filter(SpecInt32);
- if (node.op() == PutByVal)
+ if (node.op() == PutByValSafe)
clobberWorld(node.codeOrigin, indexInBlock);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -2152,10 +2152,14 @@
NodeIndex property = get(currentInstruction[2].u.operand);
NodeIndex value = get(currentInstruction[3].u.operand);
+ bool makeSafe =
+ m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds);
+
addVarArgChild(base);
addVarArgChild(property);
addVarArgChild(value);
- addToGraph(Node::VarArg, PutByVal, OpInfo(0), OpInfo(0));
+ addToGraph(Node::VarArg, makeSafe ? PutByValSafe : PutByVal, OpInfo(0), OpInfo(0));
NEXT_OPCODE(op_put_by_val);
}
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -284,7 +284,8 @@
return index;
break;
case PutByVal:
- case PutByValAlias: {
+ case PutByValAlias:
+ case PutByValSafe: {
if (!m_graph.byValIsPure(node))
return NoNode;
if (m_graph.varArgChild(node, 0) == child1 && canonicalize(m_graph.varArgChild(node, 1)) == canonicalize(child2))
@@ -362,6 +363,7 @@
case PutByVal:
case PutByValAlias:
+ case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -404,6 +406,7 @@
case PutByVal:
case PutByValAlias:
+ case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -507,6 +510,7 @@
case PutByVal:
case PutByValAlias:
+ case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -551,6 +555,7 @@
case PutByVal:
case PutByValAlias:
case GetByVal:
+ case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -603,6 +608,7 @@
case PutByVal:
case PutByValAlias:
+ case PutByValSafe:
if (m_graph.byValIsPure(node)) {
// If PutByVal speculates that it's accessing an array with an
// integer index, then it's impossible for it to cause a structure
@@ -643,15 +649,6 @@
// change the property storage pointer.
break;
- case PutByValAlias:
- // PutByValAlias can't change the indexed storage pointer
- break;
-
- case PutByVal:
- if (isFixedIndexedStorageObjectSpeculation(m_graph[m_graph.varArgChild(node, 0)].prediction()) && m_graph.byValIsPure(node))
- break;
- return NoNode;
-
default:
if (m_graph.clobbersWorld(index))
return NoNode;
@@ -1093,7 +1090,8 @@
setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index()));
break;
- case PutByVal: {
+ case PutByVal:
+ case PutByValSafe: {
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
if (isActionableMutableArraySpeculation(m_graph[child1].prediction())
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -314,7 +314,8 @@
break;
}
- case PutByVal: {
+ case PutByVal:
+ case PutByValSafe: {
Edge child1 = m_graph.varArgChild(node, 0);
Edge child2 = m_graph.varArgChild(node, 1);
Edge child3 = m_graph.varArgChild(node, 2);
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.h 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h 2012-08-02 01:28:10 UTC (rev 124398)
@@ -479,6 +479,15 @@
SpeculatedType prediction = at(varArgChild(node, 0)).prediction();
if (!isActionableMutableArraySpeculation(prediction))
return false;
+ return true;
+ }
+
+ case PutByValSafe: {
+ if (!at(varArgChild(node, 1)).shouldSpeculateInteger())
+ return false;
+ SpeculatedType prediction = at(varArgChild(node, 0)).prediction();
+ if (!isActionableMutableArraySpeculation(prediction))
+ return false;
if (isArraySpeculation(prediction))
return false;
return true;
@@ -524,6 +533,7 @@
return !isPredictedNumerical(node);
case GetByVal:
case PutByVal:
+ case PutByValSafe:
case PutByValAlias:
return !byValIsPure(node);
default:
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-08-02 01:28:10 UTC (rev 124398)
@@ -113,6 +113,7 @@
/* opcodes use VarArgs beause they may have up to 4 children. */\
macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
macro(PutByVal, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
+ macro(PutByValSafe, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -637,6 +637,7 @@
}
case PutByVal:
+ case PutByValSafe:
changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue);
changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -2483,7 +2483,8 @@
break;
}
- case PutByVal: {
+ case PutByVal:
+ case PutByValSafe: {
Edge child1 = m_jit.graph().varArgChild(node, 0);
Edge child2 = m_jit.graph().varArgChild(node, 1);
Edge child3 = m_jit.graph().varArgChild(node, 2);
@@ -2599,12 +2600,14 @@
if (!isArraySpeculation(m_state.forNode(child1).m_type))
speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), child1, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+ MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+ if (node.op() == PutByVal)
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
+
base.use();
property.use();
value.use();
- MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
-
// Get the array storage.
GPRReg storageReg = scratchReg;
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
@@ -2626,12 +2629,14 @@
m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- addSlowPathGenerator(
- slowPathCall(
- beyondArrayBounds, this,
- m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
- NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
-
+ if (node.op() == PutByValSafe) {
+ addSlowPathGenerator(
+ slowPathCall(
+ beyondArrayBounds, this,
+ m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
+ NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
+ }
+
noResult(m_compileIndex, UseChildrenCalledExplicitly);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (124397 => 124398)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-08-02 01:26:52 UTC (rev 124397)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-08-02 01:28:10 UTC (rev 124398)
@@ -2508,7 +2508,8 @@
break;
}
- case PutByVal: {
+ case PutByVal:
+ case PutByValSafe: {
Edge child1 = m_jit.graph().varArgChild(node, 0);
Edge child2 = m_jit.graph().varArgChild(node, 1);
Edge child3 = m_jit.graph().varArgChild(node, 2);
@@ -2675,13 +2676,15 @@
// If we have predicted the base to be type array, we can skip the check.
if (!isArraySpeculation(m_state.forNode(child1).m_type))
speculationCheck(BadType, JSValueRegs(baseReg), child1, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+
+ MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+ if (node.op() == PutByVal)
+ speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
base.use();
property.use();
value.use();
- MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
-
// Get the array storage.
GPRReg storageReg = scratchReg;
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
@@ -2702,11 +2705,13 @@
// Store the value to the array.
m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
- addSlowPathGenerator(
- slowPathCall(
- beyondArrayBounds, this,
- m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
- NoResult, baseReg, propertyReg, valueReg));
+ if (node.op() == PutByValSafe) {
+ addSlowPathGenerator(
+ slowPathCall(
+ beyondArrayBounds, this,
+ m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
+ NoResult, baseReg, propertyReg, valueReg));
+ }
noResult(m_compileIndex, UseChildrenCalledExplicitly);
break;