Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (129315 => 129316)
--- trunk/Source/_javascript_Core/ChangeLog 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-09-23 22:48:19 UTC (rev 129316)
@@ -1,3 +1,51 @@
+2012-09-23 Geoffrey Garen <[email protected]>
+
+ CSE for access to closure variables (get_/put_scoped_var)
+ https://bugs.webkit.org/show_bug.cgi?id=97414
+
+ Reviewed by Oliver Hunt.
+
+ I separated loading a scope from loading its storage pointer, so we can
+ CSE the storage pointer load. Then, I copied the global var CSE and adjusted
+ it for closure vars.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute): Renamed GetScopeChain => GetScope to
+ reflect renames from a few weeks ago.
+
+ Added a case for the storage pointer load, similar to object storage pointer load.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock): Added an independent node for
+ the storage pointer.
+
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::scopedVarLoadElimination):
+ (CSEPhase):
+ (JSC::DFG::CSEPhase::scopedVarStoreElimination):
+ (JSC::DFG::CSEPhase::getScopeLoadElimination):
+ (JSC::DFG::CSEPhase::getScopeRegistersLoadElimination):
+ (JSC::DFG::CSEPhase::setLocalStoreElimination):
+ (JSC::DFG::CSEPhase::performNodeCSE): Copied globalVarLoad/StoreElimination
+ and adapted the same logic to closure vars.
+
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasScopeChainDepth):
+ (JSC::DFG::Node::scope):
+ (Node):
+ * dfg/DFGNodeType.h:
+ (DFG): GetScopedVar and GetGlobalVar are no longer MustGenerate. I'm not
+ sure why they ever were. But these are simple load operations so, if they're
+ unused, they're truly dead.
+
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile): Updated for renames and split-out
+ node for getting the storage pointer.
+
2012-09-21 Geoffrey Garen <[email protected]>
Unreviewed, rolled out a line I committed by accident.
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-09-23 22:48:19 UTC (rev 129316)
@@ -1262,11 +1262,17 @@
forNode(nodeIndex).set(SpecFunction);
break;
- case GetScopeChain:
+ case GetScope:
node.setCanExit(false);
forNode(nodeIndex).set(SpecCellOther);
break;
-
+
+ case GetScopeRegisters:
+ node.setCanExit(false);
+ forNode(node.child1()).filter(SpecCell);
+ forNode(nodeIndex).clear(); // The result is not a JS value.
+ break;
+
case GetScopedVar:
node.setCanExit(false);
forNode(nodeIndex).makeTop();
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-09-23 22:48:19 UTC (rev 129316)
@@ -2265,8 +2265,9 @@
int dst = currentInstruction[1].u.operand;
int slot = currentInstruction[2].u.operand;
int depth = currentInstruction[3].u.operand;
- NodeIndex getScopeChain = addToGraph(GetScopeChain, OpInfo(depth));
- NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeChain);
+ NodeIndex getScope = addToGraph(GetScope, OpInfo(depth));
+ NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
+ NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeRegisters);
set(dst, getScopedVar);
NEXT_OPCODE(op_get_scoped_var);
}
@@ -2274,8 +2275,9 @@
int slot = currentInstruction[1].u.operand;
int depth = currentInstruction[2].u.operand;
int source = currentInstruction[3].u.operand;
- NodeIndex getScopeChain = addToGraph(GetScopeChain, OpInfo(depth));
- addToGraph(PutScopedVar, OpInfo(slot), getScopeChain, get(source));
+ NodeIndex getScope = addToGraph(GetScope, OpInfo(depth));
+ NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
+ addToGraph(PutScopedVar, OpInfo(slot), getScope, getScopeRegisters, get(source));
NEXT_OPCODE(op_put_scoped_var);
}
case op_get_by_id:
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-09-23 22:48:19 UTC (rev 129316)
@@ -215,6 +215,34 @@
return NoNode;
}
+ NodeIndex scopedVarLoadElimination(unsigned scopeChainDepth, unsigned varNumber)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ Node& node = m_graph[index];
+ switch (node.op()) {
+ case GetScopedVar: {
+ Node& getScopeRegisters = m_graph[node.child1()];
+ Node& getScope = m_graph[getScopeRegisters.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ return index;
+ break;
+ }
+ case PutScopedVar: {
+ Node& getScope = m_graph[node.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ return node.child3().index();
+ break;
+ }
+ default:
+ break;
+ }
+ if (m_graph.clobbersWorld(index))
+ break;
+ }
+ return NoNode;
+ }
+
bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer)
{
for (unsigned i = m_indexInBlock; i--;) {
@@ -266,6 +294,38 @@
return NoNode;
}
+ NodeIndex scopedVarStoreElimination(unsigned scopeChainDepth, unsigned varNumber)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ Node& node = m_graph[index];
+ if (!node.shouldGenerate())
+ continue;
+ switch (node.op()) {
+ case PutScopedVar: {
+ Node& getScope = m_graph[node.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ return index;
+ break;
+ }
+
+ case GetScopedVar: {
+ Node& getScopeRegisters = m_graph[node.child1()];
+ Node& getScope = m_graph[getScopeRegisters.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ return NoNode;
+ break;
+ }
+
+ default:
+ break;
+ }
+ if (m_graph.clobbersWorld(index) || node.canExit())
+ return NoNode;
+ }
+ return NoNode;
+ }
+
NodeIndex getByValLoadElimination(NodeIndex child1, NodeIndex child2)
{
for (unsigned i = m_indexInBlock; i--;) {
@@ -689,19 +749,35 @@
return NoNode;
}
- NodeIndex getScopeChainLoadElimination(unsigned depth)
+ NodeIndex getScopeLoadElimination(unsigned depth)
{
for (unsigned i = endIndexForPureCSE(); i--;) {
NodeIndex index = m_currentBlock->at(i);
Node& node = m_graph[index];
if (!node.shouldGenerate())
continue;
- if (node.op() == GetScopeChain
+ if (node.op() == GetScope
&& node.scopeChainDepth() == depth)
return index;
}
return NoNode;
}
+
+ NodeIndex getScopeRegistersLoadElimination(unsigned depth)
+ {
+ for (unsigned i = endIndexForPureCSE(); i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ Node& node = m_graph[index];
+ if (!node.shouldGenerate())
+ continue;
+ if (node.op() == GetScopeRegisters
+ && m_graph[node.scope()].scopeChainDepth() == depth)
+ return index;
+ }
+ return NoNode;
+ }
+
+
NodeIndex getLocalLoadElimination(VirtualRegister local, NodeIndex& relevantLocalOp, bool careAboutClobbering)
{
@@ -786,7 +862,8 @@
return result;
}
- case GetScopeChain:
+ case GetScope:
+ case GetScopeRegisters:
if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local)
result.mayBeAccessed = true;
break;
@@ -1079,11 +1156,15 @@
case GetArrayLength:
setReplacement(getArrayLengthElimination(node.child1().index()));
break;
-
- case GetScopeChain:
- setReplacement(getScopeChainLoadElimination(node.scopeChainDepth()));
+
+ case GetScope:
+ setReplacement(getScopeLoadElimination(node.scopeChainDepth()));
break;
+ case GetScopeRegisters:
+ setReplacement(getScopeRegistersLoadElimination(m_graph[node.scope()].scopeChainDepth()));
+ break;
+
// Handle nodes that are conditionally pure: these are pure, and can
// be CSE'd, so long as the prediction is the one we want.
case ValueAdd:
@@ -1105,7 +1186,14 @@
case GetGlobalVar:
setReplacement(globalVarLoadElimination(node.registerPointer()));
break;
-
+
+ case GetScopedVar: {
+ Node& getScopeRegisters = m_graph[node.child1()];
+ Node& getScope = m_graph[getScopeRegisters.child1()];
+ setReplacement(scopedVarLoadElimination(getScope.scopeChainDepth(), node.varNumber()));
+ break;
+ }
+
case GlobalVarWatchpoint:
if (globalVarWatchpointElimination(node.registerPointer()))
eliminate();
@@ -1118,6 +1206,14 @@
eliminate(globalVarStoreElimination(node.registerPointer()));
break;
+ case PutScopedVar: {
+ if (m_graph.m_fixpointState == FixpointNotConverged)
+ break;
+ Node& getScope = m_graph[node.child1()];
+ eliminate(scopedVarStoreElimination(getScope.scopeChainDepth(), node.varNumber()));
+ break;
+ }
+
case GetByVal:
if (m_graph.byValIsPure(node))
setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index()));
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2012-09-23 22:48:19 UTC (rev 129316)
@@ -466,7 +466,7 @@
bool hasScopeChainDepth()
{
- return op() == GetScopeChain;
+ return op() == GetScope;
}
unsigned scopeChainDepth()
@@ -475,6 +475,12 @@
return m_opInfo;
}
+ Edge scope()
+ {
+ ASSERT(op() == GetScopeRegisters);
+ return child1();
+ }
+
bool hasResult()
{
return m_flags & NodeResultMask;
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-09-23 22:48:19 UTC (rev 129316)
@@ -144,10 +144,11 @@
macro(GetByOffset, NodeResultJS) \
macro(PutByOffset, NodeMustGenerate) \
macro(GetArrayLength, NodeResultInt32) \
- macro(GetScopeChain, NodeResultJS) \
- macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \
+ macro(GetScope, NodeResultJS) \
+ macro(GetScopeRegisters, NodeResultStorage) \
+ macro(GetScopedVar, NodeResultJS) \
macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \
- macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
+ macro(GetGlobalVar, NodeResultJS) \
macro(PutGlobalVar, NodeMustGenerate) \
macro(GlobalVarWatchpoint, NodeMustGenerate) \
macro(PutGlobalVarCheck, NodeMustGenerate) \
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-09-23 22:48:19 UTC (rev 129316)
@@ -447,7 +447,8 @@
changed |= setPrediction(SpecInt32);
break;
}
-
+
+ case GetScopeRegisters:
case GetButterfly:
case GetIndexedPropertyStorage:
case AllocatePropertyStorage:
@@ -509,7 +510,7 @@
break;
}
- case GetScopeChain: {
+ case GetScope: {
changed |= setPrediction(SpecCellOther);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-09-23 22:48:19 UTC (rev 129316)
@@ -3371,7 +3371,7 @@
break;
}
- case GetScopeChain: {
+ case GetScope: {
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (129315 => 129316)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-09-23 17:37:15 UTC (rev 129315)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-09-23 22:48:19 UTC (rev 129316)
@@ -3380,7 +3380,7 @@
break;
}
- case GetScopeChain: {
+ case GetScope: {
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
@@ -3401,23 +3401,39 @@
cellResult(resultGPR, m_compileIndex);
break;
}
- case GetScopedVar: {
+ case GetScopeRegisters: {
SpeculateCellOperand scope(this, node.child1());
GPRTemporary result(this);
+ GPRReg scopeGPR = scope.gpr();
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultGPR);
- m_jit.loadPtr(JITCompiler::Address(resultGPR, node.varNumber() * sizeof(Register)), resultGPR);
+
+ m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR);
+ storageResult(resultGPR, m_compileIndex);
+ break;
+ }
+ case GetScopedVar: {
+ StorageOperand registers(this, node.child1());
+ GPRTemporary result(this);
+ GPRReg registersGPR = registers.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.loadPtr(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register)), resultGPR);
jsValueResult(resultGPR, m_compileIndex);
break;
}
case PutScopedVar: {
SpeculateCellOperand scope(this, node.child1());
+ StorageOperand registers(this, node.child2());
+ JSValueOperand value(this, node.child3());
GPRTemporary scratchRegister(this);
+
+ GPRReg scopeGPR = scope.gpr();
+ GPRReg registersGPR = registers.gpr();
+ GPRReg valueGPR = value.gpr();
GPRReg scratchGPR = scratchRegister.gpr();
- m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
- JSValueOperand value(this, node.child2());
- m_jit.storePtr(value.gpr(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register)));
- writeBarrier(scope.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
+
+ m_jit.storePtr(valueGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register)));
+ writeBarrier(scopeGPR, valueGPR, node.child3(), WriteBarrierForVariableAccess, scratchGPR);
noResult(m_compileIndex);
break;
}