Commit 48cdafdc authored by fpizlo@apple.com's avatar fpizlo@apple.com

Get rid of SetMyScope/SetCallee; use normal variables for the scope and callee...

Get rid of SetMyScope/SetCallee; use normal variables for the scope and callee of inlined call frames of closures
https://bugs.webkit.org/show_bug.cgi?id=122047

Reviewed by Oliver Hunt.
        
Currently we have the DFG reserve space for inline call frames at exactly the same stack
offsets that you would have gotten if the baseline interpreter/JIT had made the calls.
We need to get rid of that. One of the weirder parts of this is that we have special DFG
operations for accessing these inlined call frame headers. It's really hard for any
analysis of DFG IR to see what the liveness of any of those frame header "variables" is;
the liveness behaves like flushed arguments (it's all live until end of the inlinee) but
we don't have anything like a Flush node for those special variables.
        
This patch gets rid of the special operations for accessing inline call frame headers.
GetMyScope and GetCallee still remain, and are only for accessing the machine call
frame's scope/callee entries. The inline call frame's scope/callee now behave like
normal variables, and have Flush behavior just like inline arguments.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getDirect):
(JSC::DFG::ByteCodeParser::get):
(JSC::DFG::ByteCodeParser::setDirect):
(JSC::DFG::ByteCodeParser::set):
(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::flush):
(JSC::DFG::ByteCodeParser::InlineStackEntry::remapOperand):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::getScope):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getCalleeLoadElimination):
(JSC::DFG::CSEPhase::getMyScopeLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156594 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 28bb0b6e
2013-09-27 Filip Pizlo <fpizlo@apple.com>
Get rid of SetMyScope/SetCallee; use normal variables for the scope and callee of inlined call frames of closures
https://bugs.webkit.org/show_bug.cgi?id=122047
Reviewed by Oliver Hunt.
Currently we have the DFG reserve space for inline call frames at exactly the same stack
offsets that you would have gotten if the baseline interpreter/JIT had made the calls.
We need to get rid of that. One of the weirder parts of this is that we have special DFG
operations for accessing these inlined call frame headers. It's really hard for any
analysis of DFG IR to see what the liveness of any of those frame header "variables" is;
the liveness behaves like flushed arguments (it's all live until end of the inlinee) but
we don't have anything like a Flush node for those special variables.
This patch gets rid of the special operations for accessing inline call frame headers.
GetMyScope and GetCallee still remain, and are only for accessing the machine call
frame's scope/callee entries. The inline call frame's scope/callee now behave like
normal variables, and have Flush behavior just like inline arguments.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getDirect):
(JSC::DFG::ByteCodeParser::get):
(JSC::DFG::ByteCodeParser::setDirect):
(JSC::DFG::ByteCodeParser::set):
(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::flush):
(JSC::DFG::ByteCodeParser::InlineStackEntry::remapOperand):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::getScope):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getCalleeLoadElimination):
(JSC::DFG::CSEPhase::getMyScopeLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
2013-09-27 Filip Pizlo <fpizlo@apple.com>
Deoptimize 32-bit deoptimization
......@@ -1204,10 +1204,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
forNode(node).setType(SpecFunction);
break;
case SetCallee:
case SetMyScope:
break;
case GetScope: // FIXME: We could get rid of these if we know that the JSFunction is a constant. https://bugs.webkit.org/show_bug.cgi?id=106202
case GetMyScope:
case SkipTopScope:
......
......@@ -209,8 +209,6 @@ private:
return getJSConstant(constant);
}
ASSERT(operand.offset() != JSStack::Callee);
// Is this an argument?
if (operand.isArgument())
return getArgument(operand);
......@@ -221,32 +219,35 @@ private:
Node* get(VirtualRegister operand)
{
if (operand.offset() == JSStack::Callee) {
if (inlineCallFrame() && inlineCallFrame()->callee)
return cellConstant(inlineCallFrame()->callee.get());
return getCallee();
}
if (inlineCallFrame()) {
if (JSFunction* callee = inlineCallFrame()->callee.get()) {
if (operand.offset() == JSStack::Callee)
return cellConstant(callee);
if (operand.offset() == JSStack::ScopeChain)
return cellConstant(callee->scope());
}
} else if (operand.offset() == JSStack::Callee)
return addToGraph(GetCallee);
else if (operand.offset() == JSStack::ScopeChain)
return addToGraph(GetMyScope);
return getDirect(m_inlineStackTop->remapOperand(operand));
}
enum SetMode { NormalSet, SetOnEntry };
void setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
Node* setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
{
// Is this an argument?
if (operand.isArgument()) {
setArgument(operand, value, setMode);
return;
}
if (operand.isArgument())
return setArgument(operand, value, setMode);
// Must be a local.
setLocal(operand, value, setMode);
return setLocal(operand, value, setMode);
}
void set(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
Node* set(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
{
setDirect(m_inlineStackTop->remapOperand(operand), value, setMode);
return setDirect(m_inlineStackTop->remapOperand(operand), value, setMode);
}
Node* injectLazyOperandSpeculation(Node* node)
......@@ -302,7 +303,7 @@ private:
return node;
}
void setLocal(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
Node* setLocal(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
{
unsigned local = operand.toLocal();
bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame());
......@@ -320,6 +321,7 @@ private:
m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType));
Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.local(local) = node;
return node;
}
// Used in implementing get/set, above, where the operand is an argument.
......@@ -352,7 +354,7 @@ private:
m_currentBlock->variablesAtTail.argument(argument) = node;
return node;
}
void setArgument(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
Node* setArgument(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
{
unsigned argument = operand.toArgument();
ASSERT(argument < m_numArguments);
......@@ -375,6 +377,7 @@ private:
m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType));
Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.argument(argument) = node;
return node;
}
ArgumentPosition* findArgumentPositionForArgument(int argument)
......@@ -460,9 +463,13 @@ private:
void flush(InlineStackEntry* inlineStackEntry)
{
int numArguments;
if (InlineCallFrame* inlineCallFrame = inlineStackEntry->m_inlineCallFrame)
if (InlineCallFrame* inlineCallFrame = inlineStackEntry->m_inlineCallFrame) {
numArguments = inlineCallFrame->arguments.size();
else
if (!inlineCallFrame->callee) {
flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::Callee)));
flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::ScopeChain)));
}
} else
numArguments = inlineStackEntry->m_codeBlock->numParameters();
for (unsigned argument = numArguments; argument-- > 1;)
flushDirect(inlineStackEntry->remapOperand(virtualRegisterForArgument(argument)));
......@@ -539,11 +546,6 @@ private:
return result;
}
Node* getCallee()
{
return addToGraph(GetCallee);
}
// Helper functions to get/set the this value.
Node* getThis()
{
......@@ -1107,8 +1109,6 @@ private:
return result;
}
ASSERT(operand.offset() != JSStack::Callee);
return VirtualRegister(operand.offset() + m_inlineCallFrame->stackOffset);
}
};
......@@ -1320,8 +1320,13 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con
addToGraph(InlineStart, OpInfo(argumentPositionStart));
if (callLinkStatus.isClosureCall()) {
addToGraph(SetCallee, callTargetNode);
addToGraph(SetMyScope, addToGraph(GetScope, callTargetNode));
VariableAccessData* calleeVariable =
set(VirtualRegister(JSStack::Callee), callTargetNode)->variableAccessData();
VariableAccessData* scopeVariable =
set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode))->variableAccessData();
calleeVariable->mergeShouldNeverUnbox(true);
scopeVariable->mergeShouldNeverUnbox(true);
}
parseCodeBlock();
......@@ -1821,12 +1826,7 @@ void ByteCodeParser::prepareToParseBlock()
Node* ByteCodeParser::getScope(bool skipTop, unsigned skipCount)
{
Node* localBase;
if (inlineCallFrame() && !inlineCallFrame()->isClosureCall()) {
ASSERT(inlineCallFrame()->callee);
localBase = cellConstant(inlineCallFrame()->callee->scope());
} else
localBase = addToGraph(GetMyScope);
Node* localBase = get(VirtualRegister(JSStack::ScopeChain));
if (skipTop) {
ASSERT(!inlineCallFrame());
localBase = addToGraph(SkipTopScope, localBase);
......
......@@ -165,17 +165,13 @@ private:
return 0;
}
Node* getCalleeLoadElimination(InlineCallFrame* inlineCallFrame)
Node* getCalleeLoadElimination()
{
for (unsigned i = m_indexInBlock; i--;) {
Node* node = m_currentBlock->at(i);
if (node->codeOrigin.inlineCallFrame != inlineCallFrame)
continue;
switch (node->op()) {
case GetCallee:
return node;
case SetCallee:
return node->child1().node();
default:
break;
}
......@@ -802,20 +798,16 @@ private:
return 0;
}
Node* getMyScopeLoadElimination(InlineCallFrame* inlineCallFrame)
Node* getMyScopeLoadElimination()
{
for (unsigned i = m_indexInBlock; i--;) {
Node* node = m_currentBlock->at(i);
if (node->codeOrigin.inlineCallFrame != inlineCallFrame)
continue;
switch (node->op()) {
case CreateActivation:
// This may cause us to return a different scope.
return 0;
case GetMyScope:
return node;
case SetMyScope:
return node->child1().node();
default:
break;
}
......@@ -1091,7 +1083,7 @@ private:
case GetCallee:
if (cseMode == StoreElimination)
break;
setReplacement(getCalleeLoadElimination(node->codeOrigin.inlineCallFrame));
setReplacement(getCalleeLoadElimination());
break;
case GetLocal: {
......@@ -1189,7 +1181,7 @@ private:
case GetMyScope:
if (cseMode == StoreElimination)
break;
setReplacement(getMyScopeLoadElimination(node->codeOrigin.inlineCallFrame));
setReplacement(getMyScopeLoadElimination());
break;
// Handle nodes that are conditionally pure: these are pure, and can
......
......@@ -207,10 +207,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
read(AbstractHeap(Variables, JSStack::Callee));
return;
case SetCallee:
write(AbstractHeap(Variables, JSStack::Callee));
return;
case GetLocal:
case GetArgument:
read(AbstractHeap(Variables, node->local()));
......@@ -500,10 +496,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
read(AbstractHeap(Variables, JSStack::ScopeChain));
return;
case SetMyScope:
write(AbstractHeap(Variables, JSStack::ScopeChain));
return;
case SkipTopScope:
read(AbstractHeap(Variables, graph.m_codeBlock->activationRegister()));
return;
......
......@@ -759,8 +759,6 @@ private:
case PutClosureVar:
case SkipTopScope:
case SkipScope:
case SetCallee:
case SetMyScope:
case PutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
......
......@@ -52,7 +52,6 @@ namespace JSC { namespace DFG {
macro(ToThis, NodeResultJS) \
macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
macro(GetCallee, NodeResultJS) \
macro(SetCallee, NodeMustGenerate) \
\
/* Nodes for local variable access. These nodes are linked together using Phi nodes. */\
/* Any two nodes that are part of the same Phi graph will share the same */\
......@@ -176,7 +175,6 @@ namespace JSC { namespace DFG {
macro(GetTypedArrayByteOffset, NodeResultInt32) \
macro(GetScope, NodeResultJS) \
macro(GetMyScope, NodeResultJS) \
macro(SetMyScope, NodeMustGenerate) \
macro(SkipTopScope, NodeResultJS) \
macro(SkipScope, NodeResultJS) \
macro(GetClosureRegisters, NodeResultStorage) \
......
......@@ -552,8 +552,6 @@ private:
case PutById:
case PutByIdDirect:
case PutByOffset:
case SetCallee:
case SetMyScope:
case DFG::Jump:
case Branch:
case Switch:
......
......@@ -116,7 +116,6 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
case ToThis:
case CreateThis:
case GetCallee:
case SetCallee:
case GetLocal:
case SetLocal:
case MovHintAndCheck:
......@@ -165,7 +164,6 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
case ArrayifyToStructure:
case GetScope:
case GetMyScope:
case SetMyScope:
case SkipTopScope:
case SkipScope:
case GetClosureRegisters:
......
......@@ -3687,19 +3687,11 @@ void SpeculativeJIT::compile(Node* node)
case GetCallee: {
GPRTemporary result(this);
m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))), result.gpr());
m_jit.loadPtr(JITCompiler::payloadFor(JSStack::Callee), result.gpr());
cellResult(result.gpr(), node);
break;
}
case SetCallee: {
SpeculateCellOperand callee(this, node->child1());
m_jit.storePtr(callee.gpr(), JITCompiler::payloadFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))));
m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), JITCompiler::tagFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))));
noResult(node);
break;
}
case GetScope: {
SpeculateCellOperand function(this, node->child1());
GPRTemporary result(this, Reuse, function);
......@@ -3712,18 +3704,11 @@ void SpeculativeJIT::compile(Node* node)
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::ScopeChain))), resultGPR);
m_jit.loadPtr(JITCompiler::payloadFor(JSStack::ScopeChain), resultGPR);
cellResult(resultGPR, node);
break;
}
case SetMyScope: {
SpeculateCellOperand callee(this, node->child1());
m_jit.storePtr(callee.gpr(), JITCompiler::payloadFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::ScopeChain))));
noResult(node);
break;
}
case SkipTopScope: {
SpeculateCellOperand scope(this, node->child1());
GPRTemporary result(this, Reuse, scope);
......
......@@ -3981,18 +3981,11 @@ void SpeculativeJIT::compile(Node* node)
case GetCallee: {
GPRTemporary result(this);
m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))), result.gpr());
m_jit.loadPtr(JITCompiler::addressFor(JSStack::Callee), result.gpr());
cellResult(result.gpr(), node);
break;
}
case SetCallee: {
SpeculateCellOperand callee(this, node->child1());
m_jit.storePtr(callee.gpr(), JITCompiler::addressFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))));
noResult(node);
break;
}
case GetScope: {
SpeculateCellOperand function(this, node->child1());
GPRTemporary result(this, Reuse, function);
......@@ -4005,18 +3998,11 @@ void SpeculativeJIT::compile(Node* node)
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::ScopeChain))), resultGPR);
m_jit.loadPtr(JITCompiler::addressFor(JSStack::ScopeChain), resultGPR);
cellResult(resultGPR, node);
break;
}
case SetMyScope: {
SpeculateCellOperand callee(this, node->child1());
m_jit.storePtr(callee.gpr(), JITCompiler::addressFor(static_cast<VirtualRegister>(node->codeOrigin.stackOffset() + static_cast<int>(JSStack::ScopeChain))));
noResult(node);
break;
}
case SkipTopScope: {
SpeculateCellOperand scope(this, node->child1());
GPRTemporary result(this, Reuse, scope);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment