Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (143954 => 143955)
--- trunk/Source/_javascript_Core/ChangeLog 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-02-25 20:23:55 UTC (rev 143955)
@@ -1,3 +1,49 @@
+2013-02-22 Filip Pizlo <[email protected]>
+
+ The DFG special case checks for isCreatedThisArgument are fragile
+ https://bugs.webkit.org/show_bug.cgi?id=110535
+
+ Reviewed by Oliver Hunt.
+
+ There may be many situations in which we want to force a variable to never be
+ unboxed. Capturing is one such case, and the created this argument is another.
+ Previously all code that dealt with this issue had to query both scenarios.
+
+ Now DFG::VariableAccessData knows these things. You just have to ask
+ VariableAccessData for whether a variable should be unboxed. Anyone wishing to
+ force a variable to never be unboxed just tells VariableAccessData.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::initialize):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ (DFG):
+ * dfg/DFGCFGSimplificationPhase.cpp:
+ (CFGSimplificationPhase):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.h:
+ (Graph):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGUnificationPhase.cpp:
+ (JSC::DFG::UnificationPhase::run):
+ * dfg/DFGVariableAccessData.h:
+ (JSC::DFG::VariableAccessData::VariableAccessData):
+ (JSC::DFG::VariableAccessData::mergeIsCaptured):
+ (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox):
+ (VariableAccessData):
+ (JSC::DFG::VariableAccessData::shouldNeverUnbox):
+ (JSC::DFG::VariableAccessData::shouldUnboxIfPossible):
+ (JSC::DFG::VariableAccessData::shouldUseDoubleFormat):
+ (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat):
+
2013-02-25 Geoffrey Garen <[email protected]>
Do one lookup per code cache insertion instead of two
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -96,7 +96,7 @@
continue;
}
- if (node->variableAccessData()->isCaptured()) {
+ if (!node->variableAccessData()->shouldUnboxIfPossible()) {
root->valuesAtHead.argument(i).makeTop();
continue;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGArgumentPosition.h (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGArgumentPosition.h 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentPosition.h 2013-02-25 20:23:55 UTC (rev 143955)
@@ -37,6 +37,7 @@
ArgumentPosition()
: m_prediction(SpecNone)
, m_doubleFormatState(EmptyDoubleFormatState)
+ , m_shouldNeverUnbox(false)
{
}
@@ -45,12 +46,22 @@
m_variables.append(variable);
}
+ bool mergeShouldNeverUnbox(bool shouldNeverUnbox)
+ {
+ bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;
+ if (newShouldNeverUnbox == m_shouldNeverUnbox)
+ return false;
+ m_shouldNeverUnbox = newShouldNeverUnbox;
+ return true;
+ }
+
bool mergeArgumentAwareness()
{
bool changed = false;
for (unsigned i = 0; i < m_variables.size(); ++i) {
changed |= mergeSpeculation(m_prediction, m_variables[i]->argumentAwarePrediction());
changed |= mergeDoubleFormatState(m_doubleFormatState, m_variables[i]->doubleFormatState());
+ changed |= mergeShouldNeverUnbox(m_variables[i]->shouldNeverUnbox());
}
if (!changed)
return false;
@@ -58,6 +69,7 @@
for (unsigned i = 0; i < m_variables.size(); ++i) {
changed |= m_variables[i]->mergeArgumentAwarePrediction(m_prediction);
changed |= m_variables[i]->mergeDoubleFormatState(m_doubleFormatState);
+ changed |= m_variables[i]->mergeShouldNeverUnbox(m_shouldNeverUnbox);
}
return changed;
}
@@ -72,6 +84,7 @@
private:
SpeculatedType m_prediction;
DoubleFormatState m_doubleFormatState;
+ bool m_shouldNeverUnbox;
Vector<VariableAccessData*, 2> m_variables;
};
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -199,10 +199,6 @@
template<PhiStackType stackType>
void processPhiStack();
- void fixVariableAccessPredictions();
- // Add spill locations to nodes.
- void allocateVirtualRegisters();
-
VariableAccessData* newVariableAccessData(int operand, bool isCaptured)
{
ASSERT(operand < FirstConstantRegisterIndex);
@@ -372,11 +368,16 @@
bool isCaptured = m_codeBlock->isCaptured(operand);
- // Always flush arguments, except for 'this'.
- if (argument && setMode == NormalSet)
- flushDirect(operand);
-
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
+
+ // Always flush arguments, except for 'this'. If 'this' is created by us,
+ // then make sure that it's never unboxed.
+ if (argument) {
+ if (setMode == NormalSet)
+ flushDirect(operand);
+ } else if (m_codeBlock->specializationKind() == CodeForConstruct)
+ variableAccessData->mergeShouldNeverUnbox(true);
+
variableAccessData->mergeStructureCheckHoistingFailed(
m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
@@ -1951,6 +1952,7 @@
argumentToOperand(argument), m_codeBlock->isCaptured(argumentToOperand(argument)));
variable->mergeStructureCheckHoistingFailed(
m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
+
Node* setArgument = addToGraph(SetArgument, OpInfo(variable));
m_graph.m_arguments[argument] = setArgument;
m_currentBlock->variablesAtTail.setArgumentFirstTime(argument, setArgument);
@@ -3342,16 +3344,6 @@
}
}
-void ByteCodeParser::fixVariableAccessPredictions()
-{
- for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
- VariableAccessData* data = ""
- data->find()->predict(data->nonUnifiedPrediction());
- data->find()->mergeIsCaptured(data->isCaptured());
- data->find()->mergeStructureCheckHoistingFailed(data->structureCheckHoistingFailed());
- }
-}
-
void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BlockIndex>& possibleTargets)
{
ASSERT(!block->isLinked);
Modified: trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -305,141 +305,6 @@
}
}
- void removePotentiallyDeadPhiReference(Node* myNode, Node* phiNode, unsigned edgeIndex, bool changeRef)
- {
- if (phiNode->children.child(edgeIndex).node() != myNode)
- return;
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLogF(" Removing reference at child %u.", edgeIndex);
-#endif
- if (changeRef && phiNode->shouldGenerate())
- m_graph.deref(myNode);
- phiNode->children.removeEdgeFromBag(edgeIndex);
- }
-
- struct OperandSubstitution {
- OperandSubstitution()
- : oldChild(0)
- , newChild(0)
- {
- }
-
- explicit OperandSubstitution(Node* oldChild)
- : oldChild(oldChild)
- , newChild(oldChild)
- {
- }
-
- OperandSubstitution(Node* oldChild, Node* newChild)
- : oldChild(oldChild)
- , newChild(newChild)
- {
- ASSERT((!oldChild) == (!newChild));
- }
-
- void dump(PrintStream& out) const
- {
- if (!oldChild)
- out.printf("-");
- else
- out.printf("@%u -> @%u", oldChild->index(), newChild->index());
- }
-
- Node* oldChild;
- Node* newChild;
- };
-
- Node* skipGetLocal(Node* node)
- {
- if (!node)
- return 0;
- if (node->op() == GetLocal)
- return node->child1().node();
- return node;
- }
-
- void recordPossibleIncomingReference(
- BasicBlock* secondBlock, Operands<OperandSubstitution>& substitutions, int operand)
- {
- substitutions.operand(operand) = OperandSubstitution(
- skipGetLocal(secondBlock->variablesAtTail.operand(operand)));
- }
-
- void recordNewTarget(Operands<OperandSubstitution>& substitutions, int operand, Node* node)
- {
- ASSERT(
- node->op() == SetLocal
- || node->op() == SetArgument
- || node->op() == Flush
- || node->op() == Phi);
- substitutions.operand(operand).newChild = node;
- }
-
- void fixTailOperand(
- BasicBlock* firstBlock, BasicBlock* secondBlock, int operand,
- Operands<OperandSubstitution>& substitutions)
- {
- Node* atSecondTail = secondBlock->variablesAtTail.operand(operand);
-
- if (!atSecondTail) {
- // If the variable is dead at the end of the second block, then do nothing; essentially
- // this means that we want the tail state to reflect whatever the first block did.
- return;
- }
-
- switch (atSecondTail->op()) {
- case SetLocal:
- case Flush: {
- // The second block did interesting things to the variables, so update the tail
- // accordingly.
- firstBlock->variablesAtTail.operand(operand) = atSecondTail;
- break;
- }
-
- case Phi: {
- // Keep what was in the first block.
- ASSERT(firstBlock->variablesAtTail.operand(operand));
- recordNewTarget(substitutions, operand, skipGetLocal(firstBlock->variablesAtTail.operand(operand)));
- break;
- }
-
- case GetLocal: {
- // If it's a GetLocal on a captured var, then definitely keep what was
- // in the second block. In particular, it's possible that the first
- // block doesn't even know about this variable.
- if (atSecondTail->variableAccessData()->isCaptured()) {
- firstBlock->variablesAtTail.operand(operand) = atSecondTail;
- recordNewTarget(substitutions, operand, atSecondTail->child1().node());
- break;
- }
-
- // It's possible that the second block had a GetLocal and the first block
- // had a SetArgument or a Phi. Then update the tail. Otherwise keep what was in the
- // first block.
- Node* atFirstTail = firstBlock->variablesAtTail.operand(operand);
- ASSERT(atFirstTail);
- switch (atFirstTail->op()) {
- case SetArgument:
- case Phi:
- firstBlock->variablesAtTail.operand(operand) = atSecondTail;
- recordNewTarget(substitutions, operand, atSecondTail->child1().node());
- break;
-
- default:
- // Keep what was in the first block, and adjust the substitution to account for
- // the fact that successors will refer to the child of the GetLocal.
- ASSERT(firstBlock->variablesAtTail.operand(operand));
- recordNewTarget(substitutions, operand, skipGetLocal(firstBlock->variablesAtTail.operand(operand)));
- break;
- }
- break;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
- }
-
void mergeBlocks(
BlockIndex firstBlockIndex, BlockIndex secondBlockIndex, BlockIndex jettisonedBlockIndex)
{
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -82,8 +82,7 @@
case SetLocal: {
VariableAccessData* variable = node->variableAccessData();
- if (variable->isCaptured()
- || m_graph.isCreatedThisArgument(variable->local()))
+ if (!variable->shouldUnboxIfPossible())
break;
if (variable->shouldUseDoubleFormat()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.h 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h 2013-02-25 20:23:55 UTC (rev 143955)
@@ -514,15 +514,6 @@
return m_codeBlock->usesArguments();
}
- bool isCreatedThisArgument(int operand)
- {
- if (!operandIsArgument(operand))
- return false;
- if (operandToArgument(operand))
- return false;
- return m_codeBlock->specializationKind() == CodeForConstruct;
- }
-
unsigned numSuccessors(BasicBlock* block)
{
return block->last()->numSuccessors();
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -1022,9 +1022,6 @@
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
if (!variableAccessData->isRoot())
continue;
- if (operandIsArgument(variableAccessData->local())
- || variableAccessData->isCaptured())
- continue;
m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
}
for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i)
@@ -1033,9 +1030,6 @@
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
if (!variableAccessData->isRoot())
continue;
- if (operandIsArgument(variableAccessData->local())
- || variableAccessData->isCaptured())
- continue;
m_changed |= variableAccessData->makePredictionForDoubleFormat();
}
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -1646,7 +1646,7 @@
valueSource = ValueSource(SourceIsDead);
else if (node->variableAccessData()->isArgumentsAlias())
valueSource = ValueSource(ArgumentsSource);
- else if (node->variableAccessData()->isCaptured())
+ else if (!node->variableAccessData()->shouldUnboxIfPossible())
valueSource = ValueSource(ValueInJSStack);
else if (!node->refCount())
valueSource = ValueSource(SourceIsDead);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -1936,7 +1936,7 @@
case GetLocal: {
SpeculatedType prediction = node->variableAccessData()->prediction();
- AbstractValue& value = block()->valuesAtHead.operand(node->local());
+ AbstractValue& value = m_state.variables().operand(node->local());
// If we have no prediction for this local, then don't attempt to compile.
if (prediction == SpecNone) {
@@ -1944,61 +1944,59 @@
break;
}
- if (!node->variableAccessData()->isCaptured()) {
- // If the CFA is tracking this variable and it found that the variable
- // cannot have been assigned, then don't attempt to proceed.
- if (value.isClear()) {
- // FIXME: We should trap instead.
- // https://bugs.webkit.org/show_bug.cgi?id=110383
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
- break;
- }
+ // If the CFA is tracking this variable and it found that the variable
+ // cannot have been assigned, then don't attempt to proceed.
+ if (value.isClear()) {
+ // FIXME: We should trap instead.
+ // https://bugs.webkit.org/show_bug.cgi?id=110383
+ terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
+ break;
+ }
+
+ if (node->variableAccessData()->shouldUseDoubleFormat()) {
+ FPRTemporary result(this);
+ m_jit.loadDouble(JITCompiler::addressFor(node->local()), result.fpr());
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
+ m_generationInfo[virtualRegister].initDouble(node, node->refCount(), result.fpr());
+ break;
+ }
+
+ if (isInt32Speculation(value.m_type)) {
+ GPRTemporary result(this);
+ m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
- if (node->variableAccessData()->shouldUseDoubleFormat()) {
- FPRTemporary result(this);
- m_jit.loadDouble(JITCompiler::addressFor(node->local()), result.fpr());
- VirtualRegister virtualRegister = node->virtualRegister();
- m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
- m_generationInfo[virtualRegister].initDouble(node, node->refCount(), result.fpr());
- break;
- }
+ // Like integerResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
+ m_generationInfo[virtualRegister].initInteger(node, node->refCount(), result.gpr());
+ break;
+ }
- if (isInt32Speculation(value.m_type)) {
- GPRTemporary result(this);
- m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
-
- // Like integerResult, but don't useChildren - our children are phi nodes,
- // and don't represent values within this dataflow with virtual registers.
- VirtualRegister virtualRegister = node->virtualRegister();
- m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
- m_generationInfo[virtualRegister].initInteger(node, node->refCount(), result.gpr());
- break;
- }
-
- if (isCellSpeculation(value.m_type)) {
- GPRTemporary result(this);
- m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
-
- // Like cellResult, but don't useChildren - our children are phi nodes,
- // and don't represent values within this dataflow with virtual registers.
- VirtualRegister virtualRegister = node->virtualRegister();
- m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
- m_generationInfo[virtualRegister].initCell(node, node->refCount(), result.gpr());
- break;
- }
-
- if (isBooleanSpeculation(value.m_type)) {
- GPRTemporary result(this);
- m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
-
- // Like booleanResult, but don't useChildren - our children are phi nodes,
- // and don't represent values within this dataflow with virtual registers.
- VirtualRegister virtualRegister = node->virtualRegister();
- m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
- m_generationInfo[virtualRegister].initBoolean(node, node->refCount(), result.gpr());
- break;
- }
+ if (isCellSpeculation(value.m_type)) {
+ GPRTemporary result(this);
+ m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
+
+ // Like cellResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
+ m_generationInfo[virtualRegister].initCell(node, node->refCount(), result.gpr());
+ break;
}
+
+ if (isBooleanSpeculation(value.m_type)) {
+ GPRTemporary result(this);
+ m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
+
+ // Like booleanResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
+ m_generationInfo[virtualRegister].initBoolean(node, node->refCount(), result.gpr());
+ break;
+ }
GPRTemporary result(this);
GPRTemporary tag(this);
@@ -2011,13 +2009,7 @@
m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
- DataFormat format;
- if (isCellSpeculation(value.m_type)
- && !node->variableAccessData()->isCaptured())
- format = DataFormatJSCell;
- else
- format = DataFormatJS;
- m_generationInfo[virtualRegister].initJSValue(node, node->refCount(), tag.gpr(), result.gpr(), format);
+ m_generationInfo[virtualRegister].initJSValue(node, node->refCount(), tag.gpr(), result.gpr(), DataFormatJS);
break;
}
@@ -2037,7 +2029,7 @@
// stack.
compileMovHint(node);
- if (!node->variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node->local())) {
+ if (node->variableAccessData()->shouldUnboxIfPossible()) {
if (node->variableAccessData()->shouldUseDoubleFormat()) {
SpeculateDoubleOperand value(this, node->child1(), ForwardSpeculation);
m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->local()));
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -1902,7 +1902,7 @@
case GetLocal: {
SpeculatedType prediction = node->variableAccessData()->prediction();
- AbstractValue& value = block()->valuesAtHead.operand(node->local());
+ AbstractValue& value = m_state.variables().operand(node->local());
// If we have no prediction for this local, then don't attempt to compile.
if (prediction == SpecNone) {
@@ -1910,36 +1910,34 @@
break;
}
- if (!node->variableAccessData()->isCaptured()) {
- // If the CFA is tracking this variable and it found that the variable
- // cannot have been assigned, then don't attempt to proceed.
- if (value.isClear()) {
- // FIXME: We should trap instead.
- // https://bugs.webkit.org/show_bug.cgi?id=110383
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
- break;
- }
+ // If the CFA is tracking this variable and it found that the variable
+ // cannot have been assigned, then don't attempt to proceed.
+ if (value.isClear()) {
+ // FIXME: We should trap instead.
+ // https://bugs.webkit.org/show_bug.cgi?id=110383
+ terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
+ break;
+ }
+
+ if (node->variableAccessData()->shouldUseDoubleFormat()) {
+ FPRTemporary result(this);
+ m_jit.loadDouble(JITCompiler::addressFor(node->local()), result.fpr());
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
+ m_generationInfo[virtualRegister].initDouble(node, node->refCount(), result.fpr());
+ break;
+ }
+
+ if (isInt32Speculation(value.m_type)) {
+ GPRTemporary result(this);
+ m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
- if (node->variableAccessData()->shouldUseDoubleFormat()) {
- FPRTemporary result(this);
- m_jit.loadDouble(JITCompiler::addressFor(node->local()), result.fpr());
- VirtualRegister virtualRegister = node->virtualRegister();
- m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
- m_generationInfo[virtualRegister].initDouble(node, node->refCount(), result.fpr());
- break;
- }
-
- if (isInt32Speculation(value.m_type)) {
- GPRTemporary result(this);
- m_jit.load32(JITCompiler::payloadFor(node->local()), result.gpr());
-
- // Like integerResult, but don't useChildren - our children are phi nodes,
- // and don't represent values within this dataflow with virtual registers.
- VirtualRegister virtualRegister = node->virtualRegister();
- m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
- m_generationInfo[virtualRegister].initInteger(node, node->refCount(), result.gpr());
- break;
- }
+ // Like integerResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
+ m_generationInfo[virtualRegister].initInteger(node, node->refCount(), result.gpr());
+ break;
}
GPRTemporary result(this);
@@ -1951,9 +1949,7 @@
m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
DataFormat format;
- if (node->variableAccessData()->isCaptured())
- format = DataFormatJS;
- else if (isCellSpeculation(value.m_type))
+ if (isCellSpeculation(value.m_type))
format = DataFormatJSCell;
else if (isBooleanSpeculation(value.m_type))
format = DataFormatJSBoolean;
@@ -1980,7 +1976,7 @@
// stack.
compileMovHint(node);
- if (!node->variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node->local())) {
+ if (node->variableAccessData()->shouldUnboxIfPossible()) {
if (node->variableAccessData()->shouldUseDoubleFormat()) {
SpeculateDoubleOperand value(this, node->child1(), ForwardSpeculation);
m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->local()));
Modified: trunk/Source/_javascript_Core/dfg/DFGUnificationPhase.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGUnificationPhase.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGUnificationPhase.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -72,6 +72,7 @@
data->find()->predict(data->nonUnifiedPrediction());
data->find()->mergeIsCaptured(data->isCaptured());
data->find()->mergeStructureCheckHoistingFailed(data->structureCheckHoistingFailed());
+ data->find()->mergeShouldNeverUnbox(data->shouldNeverUnbox());
}
m_graph.m_unificationState = GloballyUnified;
Modified: trunk/Source/_javascript_Core/dfg/DFGVariableAccessData.h (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGVariableAccessData.h 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGVariableAccessData.h 2013-02-25 20:23:55 UTC (rev 143955)
@@ -46,10 +46,11 @@
, m_prediction(SpecNone)
, m_argumentAwarePrediction(SpecNone)
, m_flags(0)
- , m_doubleFormatState(EmptyDoubleFormatState)
, m_isCaptured(false)
+ , m_shouldNeverUnbox(false)
, m_isArgumentsAlias(false)
, m_structureCheckHoistingFailed(false)
+ , m_doubleFormatState(EmptyDoubleFormatState)
{
clearVotes();
}
@@ -59,10 +60,11 @@
, m_prediction(SpecNone)
, m_argumentAwarePrediction(SpecNone)
, m_flags(0)
- , m_doubleFormatState(EmptyDoubleFormatState)
, m_isCaptured(isCaptured)
+ , m_shouldNeverUnbox(isCaptured)
, m_isArgumentsAlias(false)
, m_structureCheckHoistingFailed(false)
+ , m_doubleFormatState(EmptyDoubleFormatState)
{
clearVotes();
}
@@ -80,6 +82,7 @@
bool mergeIsCaptured(bool isCaptured)
{
+ m_shouldNeverUnbox |= isCaptured;
bool newIsCaptured = m_isCaptured | isCaptured;
if (newIsCaptured == m_isCaptured)
return false;
@@ -92,6 +95,32 @@
return m_isCaptured;
}
+ bool mergeShouldNeverUnbox(bool shouldNeverUnbox)
+ {
+ bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;
+ if (newShouldNeverUnbox == m_shouldNeverUnbox)
+ return false;
+ m_shouldNeverUnbox = newShouldNeverUnbox;
+ return true;
+ }
+
+ // Returns true if it would be unsound to store the value in an unboxed fashion.
+ // If this returns false, it simply means that it is sound to unbox; it doesn't
+ // mean that we have actually done so.
+ bool shouldNeverUnbox()
+ {
+ ASSERT(!(m_isCaptured && !m_shouldNeverUnbox));
+ return m_shouldNeverUnbox;
+ }
+
+ // Returns true if we should be unboxing the value provided that the predictions
+ // and double format vote say so. This may return false even if shouldNeverUnbox()
+ // returns false, since this incorporates heuristics of profitability.
+ bool shouldUnboxIfPossible()
+ {
+ return !shouldNeverUnbox();
+ }
+
bool mergeStructureCheckHoistingFailed(bool failed)
{
bool newFailed = m_structureCheckHoistingFailed | failed;
@@ -210,13 +239,19 @@
bool shouldUseDoubleFormat()
{
ASSERT(isRoot());
- return m_doubleFormatState == UsingDoubleFormat;
+ bool result = m_doubleFormatState == UsingDoubleFormat;
+ ASSERT(!(result && shouldNeverUnbox()));
+ ASSERT(!(result && isCaptured()));
+ return result;
}
bool tallyVotesForShouldUseDoubleFormat()
{
ASSERT(isRoot());
+ if (operandIsArgument(local()) || shouldNeverUnbox())
+ return DFG::mergeDoubleFormatState(m_doubleFormatState, NotUsingDoubleFormat);
+
if (m_doubleFormatState == CantUseDoubleFormat)
return false;
@@ -270,12 +305,13 @@
SpeculatedType m_argumentAwarePrediction;
NodeFlags m_flags;
- float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
- DoubleFormatState m_doubleFormatState;
-
bool m_isCaptured;
+ bool m_shouldNeverUnbox;
bool m_isArgumentsAlias;
bool m_structureCheckHoistingFailed;
+
+ float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
+ DoubleFormatState m_doubleFormatState;
};
} } // namespace JSC::DFG
Modified: trunk/Source/_javascript_Core/dfg/DFGVariableAccessDataDump.cpp (143954 => 143955)
--- trunk/Source/_javascript_Core/dfg/DFGVariableAccessDataDump.cpp 2013-02-25 19:36:14 UTC (rev 143954)
+++ trunk/Source/_javascript_Core/dfg/DFGVariableAccessDataDump.cpp 2013-02-25 20:23:55 UTC (rev 143955)
@@ -63,6 +63,10 @@
if (m_data->isCaptured())
out.print("*");
+ else if (m_data->shouldNeverUnbox())
+ out.print("!");
+ else if (!m_data->shouldUnboxIfPossible())
+ out.print("~");
out.print(AbbreviatedSpeculationDump(m_data->prediction()));
}