summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-06-01 10:36:58 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-06-01 10:36:58 +0200
commitb1e9e47fa11f608ae16bc07f97a2acf95bf80272 (patch)
treec88c45e80c9c44506e7cdf9a3bb39ebf82a8cd5b /Source/JavaScriptCore/dfg
parentbe01689f43cf6882cf670d33df49ead1f570c53a (diff)
downloadqtwebkit-b1e9e47fa11f608ae16bc07f97a2acf95bf80272.tar.gz
Imported WebKit commit 499c84c99aa98e9870fa7eaa57db476c6d160d46 (http://svn.webkit.org/repository/webkit/trunk@119200)
Weekly update :). Particularly relevant changes for Qt are the use of the WebCore image decoders and direct usage of libpng/libjpeg if available in the system.
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp194
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp152
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp49
-rw-r--r--Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp37
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp25
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp20
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h15
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp48
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp48
11 files changed, 339 insertions, 261 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index ff737cf1d..a0849acea 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -33,21 +33,6 @@
namespace JSC { namespace DFG {
-#define CFA_PROFILING 0
-
-#if CFA_PROFILING
-#define PROFILE(flag) SamplingFlags::ScopedFlag scopedFlag(flag)
-#else
-#define PROFILE(flag) do { } while (false)
-#endif
-
-// Profiling flags
-#define FLAG_FOR_BLOCK_INITIALIZATION 17
-#define FLAG_FOR_BLOCK_END 18
-#define FLAG_FOR_EXECUTION 19
-#define FLAG_FOR_MERGE_TO_SUCCESSORS 20
-#define FLAG_FOR_STRUCTURE_CLOBBERING 21
-
AbstractState::AbstractState(Graph& graph)
: m_codeBlock(graph.m_codeBlock)
, m_graph(graph)
@@ -61,8 +46,6 @@ AbstractState::~AbstractState() { }
void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
{
- PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
-
ASSERT(!m_block);
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->valuesAtHead.numberOfLocals());
@@ -97,7 +80,6 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
void AbstractState::initialize(Graph& graph)
{
- PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
BasicBlock* root = graph.m_blocks[0].get();
root->cfaShouldRevisit = true;
root->cfaHasVisited = false;
@@ -177,7 +159,6 @@ void AbstractState::initialize(Graph& graph)
bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDirectionPtr)
{
- PROFILE(FLAG_FOR_BLOCK_END);
ASSERT(m_block);
BasicBlock* block = m_block; // Save the block for successor merging.
@@ -197,14 +178,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
dataLog(" Merging state for argument %zu.\n", argument);
#endif
AbstractValue& destination = block->valuesAtTail.argument(argument);
- NodeIndex nodeIndex = block->variablesAtTail.argument(argument);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (!destination.isTop()) {
- destination.makeTop();
- changed = true;
- }
- } else
- changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
+ changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
}
for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
@@ -212,14 +186,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
dataLog(" Merging state for local %zu.\n", local);
#endif
AbstractValue& destination = block->valuesAtTail.local(local);
- NodeIndex nodeIndex = block->variablesAtTail.local(local);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (!destination.isTop()) {
- destination.makeTop();
- changed = true;
- }
- } else
- changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
+ changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
}
}
@@ -250,7 +217,6 @@ void AbstractState::reset()
bool AbstractState::execute(unsigned indexInBlock)
{
- PROFILE(FLAG_FOR_EXECUTION);
ASSERT(m_block);
ASSERT(m_isValid);
@@ -274,11 +240,13 @@ bool AbstractState::execute(unsigned indexInBlock)
bool canExit = false;
canExit |= variableAccessData->prediction() == PredictNone;
if (variableAccessData->isCaptured())
- forNode(nodeIndex).makeTop();
+ forNode(nodeIndex) = m_variables.operand(variableAccessData->local());
else {
AbstractValue value = m_variables.operand(variableAccessData->local());
if (value.isClear())
canExit |= true;
+ if (value.value())
+ m_foundConstants = true;
forNode(nodeIndex) = value;
}
node.setCanExit(canExit);
@@ -286,13 +254,14 @@ bool AbstractState::execute(unsigned indexInBlock)
}
case GetLocalUnlinked: {
- forNode(nodeIndex).makeTop();
+ forNode(nodeIndex) = m_variables.operand(node.unlinkedLocal());
node.setCanExit(false);
break;
}
case SetLocal: {
if (node.variableAccessData()->isCaptured()) {
+ m_variables.operand(node.local()) = forNode(node.child1());
node.setCanExit(false);
break;
}
@@ -466,7 +435,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
if (node.op() == ValueAdd) {
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber);
node.setCanExit(false);
break;
@@ -772,12 +741,12 @@ bool AbstractState::execute(unsigned indexInBlock)
} else {
filter = PredictTop;
checker = isAnyPrediction;
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
}
} else {
filter = PredictTop;
checker = isAnyPrediction;
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
}
node.setCanExit(
!checker(forNode(node.child1()).m_type)
@@ -864,7 +833,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
}
@@ -958,7 +927,7 @@ bool AbstractState::execute(unsigned indexInBlock)
#endif
) {
ASSERT(node.op() == PutByVal);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
}
@@ -1241,7 +1210,10 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case CheckArgumentsNotCreated:
- node.setCanExit(true);
+ node.setCanExit(
+ !isEmptyPrediction(
+ m_variables.operand(
+ m_graph.argumentsRegisterFor(node.codeOrigin)).m_type));
break;
case GetMyArgumentsLength:
@@ -1249,20 +1221,21 @@ bool AbstractState::execute(unsigned indexInBlock)
// the arguments a bit. Note that this is not sufficient to force constant folding
// of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
// We perform further optimizations on this later on.
- if (node.codeOrigin.inlineCallFrame) {
+ if (node.codeOrigin.inlineCallFrame)
forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1));
- node.setCanExit(false);
- break;
- }
- node.setCanExit(true);
- forNode(nodeIndex).set(PredictInt32);
+ else
+ forNode(nodeIndex).set(PredictInt32);
+ node.setCanExit(
+ !isEmptyPrediction(
+ m_variables.operand(
+ m_graph.argumentsRegisterFor(node.codeOrigin)).m_type));
break;
case GetMyArgumentsLengthSafe:
node.setCanExit(false);
// This potentially clobbers all structures if the arguments object had a getter
// installed on the length property.
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
// We currently make no guarantee about what this returns because it does not
// speculate that the length property is actually a length.
forNode(nodeIndex).makeTop();
@@ -1278,10 +1251,10 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case GetMyArgumentByValSafe:
- node.setCanExit(false);
+ node.setCanExit(true);
// This potentially clobbers all structures if the property we're accessing has
// a getter. We don't speculate against this.
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
// But we do speculate that the index is an integer.
forNode(node.child1()).filter(PredictInt32);
// And the result is unknown.
@@ -1324,7 +1297,7 @@ bool AbstractState::execute(unsigned indexInBlock)
}
if (isCellPrediction(m_graph[node.child1()].prediction()))
forNode(node.child1()).filter(PredictCell);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -1502,7 +1475,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case PutByIdDirect:
node.setCanExit(true);
forNode(node.child1()).filter(PredictCell);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
break;
case GetGlobalVar:
@@ -1545,7 +1518,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case ResolveBaseStrictPut:
case ResolveGlobal:
node.setCanExit(true);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -1568,16 +1541,35 @@ bool AbstractState::execute(unsigned indexInBlock)
return m_isValid;
}
+inline void AbstractState::clobberWorld(const CodeOrigin& codeOrigin, unsigned indexInBlock)
+{
+ if (codeOrigin.inlineCallFrame) {
+ const BitVector& capturedVars = codeOrigin.inlineCallFrame->capturedVars;
+ for (size_t i = capturedVars.size(); i--;) {
+ if (!capturedVars.quickGet(i))
+ continue;
+ m_variables.local(i).makeTop();
+ }
+ } else {
+ for (size_t i = m_codeBlock->m_numCapturedVars; i--;)
+ m_variables.local(i).makeTop();
+ }
+ if (m_codeBlock->argumentsAreCaptured()) {
+ for (size_t i = m_variables.numberOfArguments(); i--;)
+ m_variables.argument(i).makeTop();
+ }
+ clobberStructures(indexInBlock);
+}
+
inline void AbstractState::clobberStructures(unsigned indexInBlock)
{
- PROFILE(FLAG_FOR_STRUCTURE_CLOBBERING);
if (!m_haveStructures)
return;
for (size_t i = indexInBlock + 1; i--;)
forNode(m_block->at(i)).clobberStructures();
- for (size_t i = 0; i < m_variables.numberOfArguments(); ++i)
+ for (size_t i = m_variables.numberOfArguments(); i--;)
m_variables.argument(i).clobberStructures();
- for (size_t i = 0; i < m_variables.numberOfLocals(); ++i)
+ for (size_t i = m_variables.numberOfLocals(); i--;)
m_variables.local(i).clobberStructures();
m_haveStructures = false;
}
@@ -1597,46 +1589,56 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
dataLog(" It's live, node @%u.\n", nodeIndex);
#endif
- switch (node.op()) {
- case Phi:
- case SetArgument:
- case Flush:
- // The block transfers the value from head to tail.
+ if (node.variableAccessData()->isCaptured()) {
source = inVariable;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Transfering ");
source.dump(WTF::dataFile());
- dataLog(" from head to tail.\n");
+ dataLog(" from last access due to captured variable.\n");
#endif
- break;
+ } else {
+ switch (node.op()) {
+ case Phi:
+ case SetArgument:
+ case Flush:
+ // The block transfers the value from head to tail.
+ source = inVariable;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Transfering ");
+ source.dump(WTF::dataFile());
+ dataLog(" from head to tail.\n");
+#endif
+ break;
- case GetLocal:
- // The block refines the value with additional speculations.
- source = forNode(nodeIndex);
+ case GetLocal:
+ // The block refines the value with additional speculations.
+ source = forNode(nodeIndex);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Refining to ");
- source.dump(WTF::dataFile());
- dataLog("\n");
+ dataLog(" Refining to ");
+ source.dump(WTF::dataFile());
+ dataLog("\n");
#endif
- break;
+ break;
- case SetLocal:
- // The block sets the variable, and potentially refines it, both
- // before and after setting it.
- if (node.variableAccessData()->shouldUseDoubleFormat())
- source.set(PredictDouble);
- else
- source = forNode(node.child1());
+ case SetLocal:
+ // The block sets the variable, and potentially refines it, both
+ // before and after setting it.
+ if (node.variableAccessData()->shouldUseDoubleFormat()) {
+ // FIXME: This unnecessarily loses precision.
+ source.set(PredictDouble);
+ } else
+ source = forNode(node.child1());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Setting to ");
- source.dump(WTF::dataFile());
- dataLog("\n");
+ dataLog(" Setting to ");
+ source.dump(WTF::dataFile());
+ dataLog("\n");
#endif
- break;
+ break;
- default:
- ASSERT_NOT_REACHED();
- break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
}
if (destination == source) {
@@ -1667,27 +1669,11 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
AbstractValue& destination = to->valuesAtHead.argument(argument);
- NodeIndex nodeIndex = from->variablesAtTail.argument(argument);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (destination.isTop())
- continue;
- destination.makeTop();
- changed = true;
- continue;
- }
changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
}
for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local) {
AbstractValue& destination = to->valuesAtHead.local(local);
- NodeIndex nodeIndex = from->variablesAtTail.local(local);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (destination.isTop())
- continue;
- destination.makeTop();
- changed = true;
- continue;
- }
changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
}
@@ -1702,8 +1688,6 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
inline bool AbstractState::mergeToSuccessors(
Graph& graph, BasicBlock* basicBlock, BranchDirection branchDirection)
{
- PROFILE(FLAG_FOR_MERGE_TO_SUCCESSORS);
-
Node& terminal = graph[basicBlock->last()];
ASSERT(terminal.isTerminal());
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index 4ce3df19b..4b0a248f3 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -136,6 +136,11 @@ public:
return forNode(nodeUse.index());
}
+ Operands<AbstractValue>& variables()
+ {
+ return m_variables;
+ }
+
// Call this before beginning CFA to initialize the abstract values of
// arguments, and to indicate which blocks should be listed for CFA
// execution.
@@ -208,7 +213,8 @@ public:
void dump(FILE* out);
private:
- void clobberStructures(unsigned);
+ void clobberWorld(const CodeOrigin&, unsigned indexInBlock);
+ void clobberStructures(unsigned indexInBlock);
bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 43157963c..358171029 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -142,20 +142,21 @@ private:
{
return getDirect(m_inlineStackTop->remapOperand(operand));
}
- void setDirect(int operand, NodeIndex value)
+ enum SetMode { NormalSet, SetOnEntry };
+ void setDirect(int operand, NodeIndex value, SetMode setMode = NormalSet)
{
// Is this an argument?
if (operandIsArgument(operand)) {
- setArgument(operand, value);
+ setArgument(operand, value, setMode);
return;
}
// Must be a local.
- setLocal((unsigned)operand, value);
+ setLocal((unsigned)operand, value, setMode);
}
- void set(int operand, NodeIndex value)
+ void set(int operand, NodeIndex value, SetMode setMode = NormalSet)
{
- setDirect(m_inlineStackTop->remapOperand(operand), value);
+ setDirect(m_inlineStackTop->remapOperand(operand), value, setMode);
}
NodeIndex injectLazyOperandPrediction(NodeIndex nodeIndex)
@@ -236,37 +237,19 @@ private:
return nodeIndex;
}
- void setLocal(unsigned operand, NodeIndex value)
+ void setLocal(unsigned operand, NodeIndex value, SetMode setMode = NormalSet)
{
bool isCaptured = m_codeBlock->localIsCaptured(m_inlineStackTop->m_inlineCallFrame, operand);
+ if (setMode == NormalSet) {
+ ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand);
+ if (isCaptured || argumentPosition)
+ flushDirect(operand, argumentPosition);
+ }
+
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
-
- bool shouldFlush = isCaptured;
-
- if (!shouldFlush) {
- // If this is in argument position, then it should be flushed.
- for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) {
- InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
- if (!inlineCallFrame)
- break;
- if (static_cast<int>(operand) >= inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize)
- continue;
- if (static_cast<int>(operand) == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset())
- continue;
- if (operand < inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size())
- continue;
- int argument = operandToArgument(operand - inlineCallFrame->stackOffset);
- stack->m_argumentPositions[argument]->addVariable(variableAccessData);
- shouldFlush = true;
- break;
- }
- }
-
- if (shouldFlush)
- addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
// Used in implementing get/set, above, where the operand is an argument.
@@ -292,7 +275,7 @@ private:
VariableAccessData* variableAccessData = flushChild.variableAccessData();
variableAccessData->mergeIsCaptured(isCaptured);
nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex));
- m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
+ m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
return nodeIndex;
}
nodePtr = &flushChild;
@@ -336,31 +319,70 @@ private:
return nodeIndex;
}
- void setArgument(int operand, NodeIndex value)
+ void setArgument(int operand, NodeIndex value, SetMode setMode = NormalSet)
{
unsigned argument = operandToArgument(operand);
bool isCaptured = m_codeBlock->argumentIsCaptured(argument);
ASSERT(argument < m_numArguments);
+ // Always flush arguments, except for 'this'.
+ if (argument && setMode == NormalSet)
+ flushDirect(operand);
+
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
- InlineStackEntry* stack = m_inlineStackTop;
- while (stack->m_inlineCallFrame) // find the machine stack entry.
- stack = stack->m_caller;
- stack->m_argumentPositions[argument]->addVariable(variableAccessData);
NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
- // Always flush arguments, except for 'this'.
- if (argument)
- addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
- VariableAccessData* flushArgument(int operand)
+ ArgumentPosition* findArgumentPositionForArgument(int argument)
+ {
+ InlineStackEntry* stack = m_inlineStackTop;
+ while (stack->m_inlineCallFrame)
+ stack = stack->m_caller;
+ return stack->m_argumentPositions[argument];
+ }
+
+ ArgumentPosition* findArgumentPositionForLocal(int operand)
+ {
+ for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) {
+ InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
+ if (!inlineCallFrame)
+ break;
+ if (operand >= inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize)
+ continue;
+ if (operand == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset())
+ continue;
+ if (static_cast<unsigned>(operand) < inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size())
+ continue;
+ int argument = operandToArgument(operand - inlineCallFrame->stackOffset);
+ return stack->m_argumentPositions[argument];
+ }
+ return 0;
+ }
+
+ ArgumentPosition* findArgumentPosition(int operand)
+ {
+ if (operandIsArgument(operand))
+ return findArgumentPositionForArgument(operandToArgument(operand));
+ return findArgumentPositionForLocal(operand);
+ }
+
+ void flush(int operand)
+ {
+ flushDirect(m_inlineStackTop->remapOperand(operand));
+ }
+
+ void flushDirect(int operand)
+ {
+ flushDirect(operand, findArgumentPosition(operand));
+ }
+
+ void flushDirect(int operand, ArgumentPosition* argumentPosition)
{
// FIXME: This should check if the same operand had already been flushed to
// some other local variable.
- operand = m_inlineStackTop->remapOperand(operand);
bool isCaptured = m_codeBlock->isCaptured(m_inlineStackTop->m_inlineCallFrame, operand);
ASSERT(operand < FirstConstantRegisterIndex);
@@ -398,7 +420,9 @@ private:
VariableAccessData* variableAccessData = node.variableAccessData();
variableAccessData->mergeIsCaptured(isCaptured);
addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
- return variableAccessData;
+ if (argumentPosition)
+ argumentPosition->addVariable(variableAccessData);
+ return;
}
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
@@ -413,7 +437,21 @@ private:
m_currentBlock->variablesAtTail.local(index) = nodeIndex;
m_currentBlock->variablesAtHead.setLocalFirstTime(index, nodeIndex);
}
- return variableAccessData;
+ if (argumentPosition)
+ argumentPosition->addVariable(variableAccessData);
+ }
+
+ void flushArgumentsAndCapturedVariables()
+ {
+ int numArguments;
+ if (m_inlineStackTop->m_inlineCallFrame)
+ numArguments = m_inlineStackTop->m_inlineCallFrame->arguments.size();
+ else
+ numArguments = m_inlineStackTop->m_codeBlock->numParameters();
+ for (unsigned argument = numArguments; argument-- > 1;)
+ flush(argumentToOperand(argument));
+ for (unsigned local = m_inlineStackTop->m_codeBlock->m_numCapturedVars; local--;)
+ flush(local);
}
// Get an operand, and perform a ToInt32/ToNumber conversion on it.
@@ -1219,17 +1257,6 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// FIXME: Don't flush constants!
- Vector<VariableAccessData*, 8> arguments;
- for (int i = 1; i < argumentCountIncludingThis; ++i) {
- VariableAccessData* variableAccessData =
- flushArgument(registerOffset + argumentToOperand(i));
- arguments.append(variableAccessData);
-
- // Are we going to be capturing arguments? If so make sure we record this fact.
- if (codeBlock->argumentIsCaptured(i))
- variableAccessData->mergeIsCaptured(true);
- }
-
int inlineCallFrameStart = m_inlineStackTop->remapOperand(registerOffset) - RegisterFile::CallFrameHeaderSize;
// Make sure that the area used by the call frame is reserved.
@@ -1251,13 +1278,6 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
usesResult ? resultOperand : InvalidVirtualRegister),
(VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind);
- // Link up the argument variable access datas to their argument positions.
- for (int i = 1; i < argumentCountIncludingThis; ++i) {
- if (static_cast<size_t>(i) >= inlineStackEntry.m_argumentPositions.size())
- break;
- inlineStackEntry.m_argumentPositions[i]->addVariable(arguments[i - 1]);
- }
-
// This is where the actual inlining really happens.
unsigned oldIndex = m_currentIndex;
unsigned oldProfilingIndex = m_currentProfilingIndex;
@@ -1578,7 +1598,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_enter:
// Initialize all locals to undefined.
for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i)
- set(i, constantUndefined());
+ set(i, constantUndefined(), SetOnEntry);
NEXT_OPCODE(op_enter);
case op_convert_this: {
@@ -2352,6 +2372,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
}
case op_ret:
+ flushArgumentsAndCapturedVariables();
if (m_inlineStackTop->m_inlineCallFrame) {
if (m_inlineStackTop->m_returnValue != InvalidVirtualRegister)
setDirect(m_inlineStackTop->m_returnValue, get(currentInstruction[1].u.operand));
@@ -2379,15 +2400,18 @@ bool ByteCodeParser::parseBlock(unsigned limit)
LAST_OPCODE(op_ret);
case op_end:
+ flushArgumentsAndCapturedVariables();
ASSERT(!m_inlineStackTop->m_inlineCallFrame);
addToGraph(Return, get(currentInstruction[1].u.operand));
LAST_OPCODE(op_end);
case op_throw:
+ flushArgumentsAndCapturedVariables();
addToGraph(Throw, get(currentInstruction[1].u.operand));
LAST_OPCODE(op_throw);
case op_throw_reference_error:
+ flushArgumentsAndCapturedVariables();
addToGraph(ThrowReferenceError);
LAST_OPCODE(op_throw_reference_error);
@@ -2818,8 +2842,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
, m_didEarlyReturn(false)
, m_caller(byteCodeParser->m_inlineStackTop)
{
- m_argumentPositions.resize(codeBlock->numParameters());
- for (unsigned i = codeBlock->numParameters(); i--;) {
+ m_argumentPositions.resize(argumentCountIncludingThis);
+ for (unsigned i = argumentCountIncludingThis; i--;) {
byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition());
ArgumentPosition* argumentPosition = &byteCodeParser->m_graph.m_argumentPositions.last();
m_argumentPositions[i] = argumentPosition;
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 3eeb70e05..31488cb1c 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -620,7 +620,7 @@ private:
}
// This returns the Flush node that is keeping a SetLocal alive.
- NodeIndex setLocalStoreElimination(VirtualRegister local)
+ NodeIndex setLocalStoreElimination(VirtualRegister local, NodeIndex expectedNodeIndex)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -629,7 +629,7 @@ private:
continue;
switch (node.op()) {
case GetLocal:
- case SetLocal:
+ case Flush:
if (node.local() == local)
return NoNode;
break;
@@ -639,19 +639,13 @@ private:
return NoNode;
break;
- case Flush: {
+ case SetLocal: {
if (node.local() != local)
break;
- if (!i)
- break;
- NodeIndex prevIndex = m_currentBlock->at(i - 1);
- if (prevIndex != node.child1().index())
- break;
- ASSERT(m_graph[prevIndex].local() == local);
- ASSERT(m_graph[prevIndex].variableAccessData() == node.variableAccessData());
- ASSERT(m_graph[prevIndex].shouldGenerate());
- if (m_graph[prevIndex].refCount() > 1)
- break;
+ if (index != expectedNodeIndex)
+ return NoNode;
+ if (m_graph[index].refCount() > 1)
+ return NoNode;
return index;
}
@@ -660,6 +654,14 @@ private:
return NoNode;
break;
+ case TearOffActivation:
+ case TearOffArguments:
+ // If an activation is being torn off then it means that captured variables
+ // are live. We could be clever here and check if the local qualifies as an
+ // argument register. But that seems like it would buy us very little since
+ // any kind of tear offs are rare to begin with.
+ return NoNode;
+
default:
if (m_graph.clobbersWorld(index))
return NoNode;
@@ -855,27 +857,26 @@ private:
break;
}
- case SetLocal: {
+ case Flush: {
if (m_fixpointState == FixpointNotConverged)
break;
VariableAccessData* variableAccessData = node.variableAccessData();
if (!variableAccessData->isCaptured())
break;
VirtualRegister local = variableAccessData->local();
- NodeIndex replacementIndex = setLocalStoreElimination(local);
+ NodeIndex replacementIndex = setLocalStoreElimination(local, node.child1().index());
if (replacementIndex == NoNode)
break;
Node& replacement = m_graph[replacementIndex];
- ASSERT(replacement.op() == Flush);
+ ASSERT(replacement.op() == SetLocal);
ASSERT(replacement.refCount() == 1);
ASSERT(replacement.shouldGenerate());
- ASSERT(replacement.mustGenerate());
- replacement.setOpAndDefaultFlags(Phantom);
- NodeIndex setLocalIndex = replacement.child1().index();
- ASSERT(m_graph[setLocalIndex].op() == SetLocal);
- m_graph.clearAndDerefChild1(replacement);
- replacement.children.child1() = m_graph[setLocalIndex].child1();
- m_graph.ref(replacement.child1());
+ node.setOpAndDefaultFlags(Phantom);
+ NodeIndex dataNodeIndex = replacement.child1().index();
+ ASSERT(m_graph[dataNodeIndex].hasResult());
+ m_graph.clearAndDerefChild1(node);
+ node.children.child1() = Edge(dataNodeIndex);
+ m_graph.ref(dataNodeIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index b2b74ba04..1e75ddea1 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -77,13 +77,42 @@ public:
ASSERT(m_graph[node.child1()].op() == Phi);
ASSERT(!m_graph[node.child1()].hasResult());
- ASSERT(block->variablesAtHead.operand(node.local()) == nodeIndex);
- ASSERT(block->isInPhis(node.child1().index()));
- block->variablesAtHead.operand(node.local()) = node.child1().index();
+ NodeIndex previousLocalAccess = NoNode;
+ if (block->variablesAtHead.operand(node.local()) == nodeIndex) {
+ // We expect this to be the common case.
+ ASSERT(block->isInPhis(node.child1().index()));
+ previousLocalAccess = node.child1().index();
+ block->variablesAtHead.operand(node.local()) = previousLocalAccess;
+ } else {
+ ASSERT(indexInBlock > 0);
+ // Must search for the previous access to this local.
+ for (BlockIndex subIndexInBlock = indexInBlock - 1; subIndexInBlock--;) {
+ NodeIndex subNodeIndex = block->at(subIndexInBlock);
+ Node& subNode = m_graph[subNodeIndex];
+ if (!subNode.shouldGenerate())
+ continue;
+ if (!subNode.hasVariableAccessData())
+ continue;
+ if (subNode.local() != node.local())
+ continue;
+ // The two must have been unified.
+ ASSERT(subNode.variableAccessData() == node.variableAccessData());
+ // Currently, the previous node must be a flush.
+ // NOTE: This assertion should be removed if we ever do
+ // constant folding on captured variables. In particular,
+ // this code does not require the previous node to be a flush,
+ // but we are asserting this anyway because it is a constraint
+ // of the IR and this is as good a place as any to assert it.
+ ASSERT(subNode.op() == Flush);
+ previousLocalAccess = subNodeIndex;
+ break;
+ }
+ ASSERT(previousLocalAccess != NoNode);
+ }
NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local());
if (tailNodeIndex == nodeIndex)
- block->variablesAtTail.operand(node.local()) = node.child1().index();
+ block->variablesAtTail.operand(node.local()) = previousLocalAccess;
else {
ASSERT(m_graph[tailNodeIndex].op() == Flush
|| m_graph[tailNodeIndex].op() == SetLocal);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index 360165b24..d3ff3be07 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -304,6 +304,10 @@ public:
void noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer)
{
#if DFG_ENABLE(OSR_ENTRY)
+ // OSR entry is not allowed into blocks deemed unreachable by control flow analysis.
+ if (!basicBlock.cfaHasVisited)
+ return;
+
OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead));
entry->m_expectedValues = basicBlock.valuesAtHead;
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index f95b993d7..b5ac4601a 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -34,6 +34,7 @@
#include "GetterSetter.h"
#include <wtf/InlineASM.h>
#include "Interpreter.h"
+#include "JITExceptions.h"
#include "JSActivation.h"
#include "JSGlobalData.h"
#include "JSStaticScopeObject.h"
@@ -1149,35 +1150,31 @@ DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
-
+
JSValue exceptionValue = exec->exception();
ASSERT(exceptionValue);
-
+
unsigned vPCIndex = exec->codeBlock()->bytecodeOffsetForCallAtIndex(callIndex);
- HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);
-
- void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
- ASSERT(catchRoutine);
- return dfgHandlerEncoded(exec, catchRoutine);
+ ExceptionHandler handler = genericThrow(globalData, exec, exceptionValue, vPCIndex);
+ ASSERT(handler.catchRoutine);
+ return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
}
DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState* exec, StructureStubInfo* stubInfo)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
-
+
JSValue exceptionValue = exec->exception();
ASSERT(exceptionValue);
CodeOrigin codeOrigin = stubInfo->codeOrigin;
while (codeOrigin.inlineCallFrame)
codeOrigin = codeOrigin.inlineCallFrame->caller;
-
- HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, codeOrigin.bytecodeIndex);
-
- void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
- ASSERT(catchRoutine);
- return dfgHandlerEncoded(exec, catchRoutine);
+
+ ExceptionHandler handler = genericThrow(globalData, exec, exceptionValue, codeOrigin.bytecodeIndex);
+ ASSERT(handler.catchRoutine);
+ return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
}
double DFG_OPERATION dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index caa21aabf..9b82121b3 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -967,6 +967,16 @@ void SpeculativeJIT::compile(BasicBlock& block)
if (!block.isReachable)
return;
+
+ if (!block.cfaHasVisited) {
+ // Don't generate code for basic blocks that are unreachable according to CFA.
+ // But to be sure that nobody has generated a jump to this block, drop in a
+ // breakpoint here.
+#if !ASSERT_DISABLED
+ m_jit.breakpoint();
+#endif
+ return;
+ }
m_blockHeads[m_block] = m_jit.label();
#if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
@@ -990,20 +1000,18 @@ void SpeculativeJIT::compile(BasicBlock& block)
ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals());
for (size_t i = 0; i < m_variables.size(); ++i) {
NodeIndex nodeIndex = block.variablesAtHead.local(i);
- // FIXME: Use the variable access data, not the first node in the block.
- // https://bugs.webkit.org/show_bug.cgi?id=87205
- if (m_jit.codeBlock()->localIsCaptured(at(block[0]).codeOrigin.inlineCallFrame, i))
- m_variables[i] = ValueSource(ValueInRegisterFile);
- else if (nodeIndex == NoNode)
+ if (nodeIndex == NoNode)
m_variables[i] = ValueSource(SourceIsDead);
else if (at(nodeIndex).variableAccessData()->isArgumentsAlias())
m_variables[i] = ValueSource(ArgumentsSource);
+ else if (at(nodeIndex).variableAccessData()->isCaptured())
+ m_variables[i] = ValueSource(ValueInRegisterFile);
else if (!at(nodeIndex).refCount())
m_variables[i] = ValueSource(SourceIsDead);
else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat())
m_variables[i] = ValueSource(DoubleInRegisterFile);
else
- m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
+ m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->argumentAwarePrediction());
}
m_lastSetOperand = std::numeric_limits<int>::max();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 912078a79..56a1a1861 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2191,22 +2191,23 @@ public:
unsigned setLocalIndexInBlock = m_indexInBlock + 1;
Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock));
+ bool hadInt32ToDouble = false;
if (setLocal->op() == Int32ToDouble) {
setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+ hadInt32ToDouble = true;
+ }
+ if (setLocal->op() == Flush)
+ setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+
+ if (hadInt32ToDouble)
ASSERT(at(setLocal->child1()).child1() == m_compileIndex);
- } else
+ else
ASSERT(setLocal->child1() == m_compileIndex);
-
ASSERT(setLocal->op() == SetLocal);
ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
Node* nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1));
- if (nextNode->codeOrigin == at(m_compileIndex).codeOrigin) {
- ASSERT(nextNode->op() == Flush);
- nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 2));
- ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin); // duplicate the same assertion as below so that if we fail, we'll know we came down this path.
- }
ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 6c0093e41..00a83000a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3858,12 +3858,16 @@ void SpeculativeJIT::compile(Node& node)
}
case CheckArgumentsNotCreated: {
- speculationCheck(
- Uncountable, JSValueRegs(), NoNode,
- m_jit.branch32(
- JITCompiler::NotEqual,
- JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
- TrustedImm32(JSValue::EmptyValueTag)));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ JITCompiler::NotEqual,
+ JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ }
noResult(m_compileIndex);
break;
}
@@ -3872,12 +3876,16 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branch32(
- JITCompiler::NotEqual,
- JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
- TrustedImm32(JSValue::EmptyValueTag)));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ JITCompiler::NotEqual,
+ JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ }
ASSERT(!node.codeOrigin.inlineCallFrame);
m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
@@ -3929,12 +3937,16 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultPayloadGPR = resultPayload.gpr();
GPRReg resultTagGPR = resultTag.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branch32(
- JITCompiler::NotEqual,
- JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
- TrustedImm32(JSValue::EmptyValueTag)));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ JITCompiler::NotEqual,
+ JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ }
m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index e4939b23a..ca57743a6 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3880,12 +3880,16 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::addressFor(
- m_jit.argumentsRegisterFor(node.codeOrigin))));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branchTestPtr(
+ JITCompiler::NonZero,
+ JITCompiler::addressFor(
+ m_jit.argumentsRegisterFor(node.codeOrigin))));
+ }
ASSERT(!node.codeOrigin.inlineCallFrame);
m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
@@ -3935,12 +3939,16 @@ void SpeculativeJIT::compile(Node& node)
GPRReg indexGPR = index.gpr();
GPRReg resultGPR = result.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::addressFor(
- m_jit.argumentsRegisterFor(node.codeOrigin))));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branchTestPtr(
+ JITCompiler::NonZero,
+ JITCompiler::addressFor(
+ m_jit.argumentsRegisterFor(node.codeOrigin))));
+ }
m_jit.add32(TrustedImm32(1), indexGPR, resultGPR);
if (node.codeOrigin.inlineCallFrame) {
@@ -4024,12 +4032,16 @@ void SpeculativeJIT::compile(Node& node)
}
case CheckArgumentsNotCreated: {
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::addressFor(
- m_jit.argumentsRegisterFor(node.codeOrigin))));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branchTestPtr(
+ JITCompiler::NonZero,
+ JITCompiler::addressFor(
+ m_jit.argumentsRegisterFor(node.codeOrigin))));
+ }
noResult(m_compileIndex);
break;
}