summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp170
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.h12
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractValue.h5
-rw-r--r--Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp17
-rw-r--r--Source/JavaScriptCore/dfg/DFGBasicBlock.h9
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeCache.h9
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp230
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h14
-rw-r--r--Source/JavaScriptCore/dfg/DFGCFAPhase.cpp10
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp163
-rw-r--r--Source/JavaScriptCore/dfg/DFGCapabilities.h34
-rw-r--r--Source/JavaScriptCore/dfg/DFGCommon.h7
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.cpp9
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp25
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h41
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.cpp22
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.h9
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.cpp81
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h282
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp36
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp28
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp69
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGPhase.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp52
-rw-r--r--Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp176
-rw-r--r--Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h49
-rw-r--r--Source/JavaScriptCore/dfg/DFGScoreBoard.h24
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp143
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h101
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp265
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp251
-rw-r--r--Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp79
33 files changed, 1726 insertions, 706 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index ee0cc9ab7..7ab05f329 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -54,13 +54,7 @@ AbstractState::AbstractState(Graph& graph)
, m_variables(m_codeBlock->numParameters(), graph.m_localVars)
, m_block(0)
{
- size_t maxBlockSize = 0;
- for (size_t i = 0; i < graph.m_blocks.size(); ++i) {
- BasicBlock* block = graph.m_blocks[i].get();
- if (block->end - block->begin > maxBlockSize)
- maxBlockSize = block->end - block->begin;
- }
- m_nodes.resize(maxBlockSize);
+ m_nodes.resize(graph.size());
}
AbstractState::~AbstractState() { }
@@ -75,8 +69,9 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals());
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
- for (size_t i = 0; i < basicBlock->end - basicBlock->begin; ++i)
- m_nodes[i].clear();
+ for (size_t i = 0; i < basicBlock->size(); i++)
+ m_nodes[basicBlock->at(i)].clear();
+
m_variables = basicBlock->valuesAtHead;
m_haveStructures = false;
for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) {
@@ -113,6 +108,11 @@ void AbstractState::initialize(Graph& graph)
continue;
}
+ if (graph.argumentIsCaptured(i)) {
+ root->valuesAtHead.argument(i).makeTop();
+ continue;
+ }
+
PredictedType prediction = node.variableAccessData()->prediction();
if (isInt32Prediction(prediction))
root->valuesAtHead.argument(i).set(PredictInt32);
@@ -143,6 +143,11 @@ void AbstractState::initialize(Graph& graph)
else
root->valuesAtHead.argument(i).makeTop();
}
+ for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
+ if (!graph.localIsCaptured(i))
+ continue;
+ root->valuesAtHead.local(i).makeTop();
+ }
}
bool AbstractState::endBasicBlock(MergeMode mergeMode)
@@ -164,14 +169,28 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode)
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging state for argument %zu.\n", argument);
#endif
- changed |= mergeStateAtTail(block->valuesAtTail.argument(argument), m_variables.argument(argument), block->variablesAtTail.argument(argument));
+ AbstractValue& destination = block->valuesAtTail.argument(argument);
+ if (m_graph.argumentIsCaptured(argument)) {
+ if (!destination.isTop()) {
+ destination.makeTop();
+ changed = true;
+ }
+ } else
+ changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
}
for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging state for local %zu.\n", local);
#endif
- changed |= mergeStateAtTail(block->valuesAtTail.local(local), m_variables.local(local), block->variablesAtTail.local(local));
+ AbstractValue& destination = block->valuesAtTail.local(local);
+ if (m_graph.localIsCaptured(local)) {
+ if (!destination.isTop()) {
+ destination.makeTop();
+ changed = true;
+ }
+ } else
+ changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
}
}
@@ -191,12 +210,13 @@ void AbstractState::reset()
m_isValid = false;
}
-bool AbstractState::execute(NodeIndex nodeIndex)
+bool AbstractState::execute(unsigned indexInBlock)
{
PROFILE(FLAG_FOR_EXECUTION);
ASSERT(m_block);
ASSERT(m_isValid);
+ NodeIndex nodeIndex = m_block->at(indexInBlock);
Node& node = m_graph[nodeIndex];
if (!node.shouldGenerate())
@@ -216,11 +236,17 @@ bool AbstractState::execute(NodeIndex nodeIndex)
}
case GetLocal: {
- forNode(nodeIndex) = m_variables.operand(node.local());
+ if (m_graph.isCaptured(node.local()))
+ forNode(nodeIndex).makeTop();
+ else
+ forNode(nodeIndex) = m_variables.operand(node.local());
break;
}
case SetLocal: {
+ if (m_graph.isCaptured(node.local()))
+ break;
+
if (node.variableAccessData()->shouldUseDoubleFormat()) {
forNode(node.child1()).filter(PredictNumber);
m_variables.operand(node.local()).set(PredictDouble);
@@ -265,12 +291,12 @@ bool AbstractState::execute(NodeIndex nodeIndex)
break;
case ValueToInt32:
- if (!m_graph[node.child1()].shouldNotSpeculateInteger()) {
+ if (m_graph[node.child1()].shouldNotSpeculateInteger()) {
if (m_graph[node.child1()].shouldSpeculateDouble())
forNode(node.child1()).filter(PredictNumber);
- else
- forNode(node.child1()).filter(PredictInt32);
- }
+ } else
+ forNode(node.child1()).filter(PredictInt32);
+
forNode(nodeIndex).set(PredictInt32);
break;
@@ -289,7 +315,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
break;
}
if (node.op == ValueAdd) {
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber);
break;
}
@@ -311,6 +337,17 @@ bool AbstractState::execute(NodeIndex nodeIndex)
break;
}
+ case ArithNegate: {
+ if (m_graph.negateShouldSpeculateInteger(node)) {
+ forNode(node.child1()).filter(PredictInt32);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+ }
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictDouble);
+ break;
+ }
+
case ArithMul:
case ArithDiv:
case ArithMin:
@@ -368,7 +405,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
else if (child.shouldSpeculateNumber())
forNode(node.child1()).filter(PredictNumber);
else
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(nodeIndex).set(PredictBoolean);
break;
}
@@ -391,7 +428,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
filter = PredictArray;
else {
filter = PredictTop;
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
}
forNode(node.child1()).filter(filter);
forNode(node.child2()).filter(filter);
@@ -421,7 +458,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
break;
}
if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(nodeIndex).makeTop();
break;
}
@@ -507,7 +544,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
}
if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArrayPrediction(m_graph[node.child1()].prediction())) {
ASSERT(node.op == PutByVal);
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(nodeIndex).makeTop();
break;
}
@@ -693,10 +730,25 @@ bool AbstractState::execute(NodeIndex nodeIndex)
}
case NewObject:
- forNode(nodeIndex).set(m_codeBlock->globalObject()->emptyObjectStructure());
+ forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->emptyObjectStructure());
m_haveStructures = true;
break;
-
+
+ case CreateActivation:
+ forNode(nodeIndex).set(m_graph.m_globalData.activationStructure.get());
+ m_haveStructures = true;
+ break;
+
+ case TearOffActivation:
+ // Does nothing that is user-visible.
+ break;
+
+ case NewFunction:
+ case NewFunctionExpression:
+ case NewFunctionNoCheck:
+ forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->functionStructure());
+ break;
+
case GetCallee:
forNode(nodeIndex).set(PredictFunction);
break;
@@ -710,7 +762,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
break;
case PutScopedVar:
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
break;
case GetById:
@@ -721,7 +773,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
}
if (isCellPrediction(m_graph[node.child1()].prediction()))
forNode(node.child1()).filter(PredictCell);
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -783,7 +835,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
break;
case PutStructure:
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(node.child1()).set(node.structureTransitionData().newStructure);
m_haveStructures = true;
break;
@@ -874,7 +926,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
case PutById:
case PutByIdDirect:
forNode(node.child1()).filter(PredictCell);
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
break;
case GetGlobalVar:
@@ -910,7 +962,7 @@ bool AbstractState::execute(NodeIndex nodeIndex)
case ResolveBase:
case ResolveBaseStrictPut:
case ResolveGlobal:
- clobberStructures(nodeIndex);
+ clobberStructures(indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -927,13 +979,13 @@ bool AbstractState::execute(NodeIndex nodeIndex)
return m_isValid;
}
-inline void AbstractState::clobberStructures(NodeIndex nodeIndex)
+inline void AbstractState::clobberStructures(unsigned indexInBlock)
{
PROFILE(FLAG_FOR_STRUCTURE_CLOBBERING);
if (!m_haveStructures)
return;
- for (size_t i = nodeIndex - m_block->begin + 1; i-- > 0;)
- m_nodes[i].clobberStructures();
+ for (size_t i = indexInBlock + 1; i--;)
+ forNode(m_block->at(i)).clobberStructures();
for (size_t i = 0; i < m_variables.numberOfArguments(); ++i)
m_variables.argument(i).clobberStructures();
for (size_t i = 0; i < m_variables.numberOfLocals(); ++i)
@@ -946,7 +998,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
if (nodeIndex == NoNode)
return false;
- AbstractValue* source;
+ AbstractValue source;
Node& node = m_graph[nodeIndex];
if (!node.refCount())
@@ -961,7 +1013,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
case SetArgument:
case Flush:
// The block transfers the value from head to tail.
- source = &inVariable;
+ source = inVariable;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Transfering from head to tail.\n");
#endif
@@ -969,7 +1021,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
case GetLocal:
// The block refines the value with additional speculations.
- source = &forNode(nodeIndex);
+ source = forNode(nodeIndex);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Refining.\n");
#endif
@@ -978,7 +1030,10 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
case SetLocal:
// The block sets the variable, and potentially refines it, both
// before and after setting it.
- source = &forNode(node.child1());
+ if (node.variableAccessData()->shouldUseDoubleFormat())
+ source.set(PredictDouble);
+ else
+ source = forNode(node.child1());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Setting.\n");
#endif
@@ -986,11 +1041,10 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
default:
ASSERT_NOT_REACHED();
- source = 0;
break;
}
- if (destination == *source) {
+ if (destination == source) {
// Abstract execution did not change the output value of the variable, for this
// basic block, on this iteration.
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
@@ -1002,7 +1056,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
// Abstract execution reached a new conclusion about the speculations reached about
// this variable after execution of this basic block. Update the state, and return
// true to indicate that the fixpoint must go on!
- destination = *source;
+ destination = source;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Changed!\n");
#endif
@@ -1016,11 +1070,29 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
bool changed = false;
- for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument)
- changed |= mergeVariableBetweenBlocks(to->valuesAtHead.argument(argument), from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
+ for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
+ AbstractValue& destination = to->valuesAtHead.argument(argument);
+ if (m_graph.argumentIsCaptured(argument)) {
+ 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)
- changed |= mergeVariableBetweenBlocks(to->valuesAtHead.local(local), from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
+ for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local) {
+ AbstractValue& destination = to->valuesAtHead.local(local);
+ if (m_graph.localIsCaptured(local)) {
+ if (destination.isTop())
+ continue;
+ destination.makeTop();
+ changed = true;
+ continue;
+ }
+ changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
+ }
if (!to->cfaHasVisited)
changed = true;
@@ -1034,7 +1106,7 @@ inline bool AbstractState::mergeToSuccessors(Graph& graph, BasicBlock* basicBloc
{
PROFILE(FLAG_FOR_MERGE_TO_SUCCESSORS);
- Node& terminal = graph[basicBlock->end - 1];
+ Node& terminal = graph[basicBlock->last()];
ASSERT(terminal.isTerminal());
@@ -1073,15 +1145,17 @@ inline bool AbstractState::mergeVariableBetweenBlocks(AbstractValue& destination
void AbstractState::dump(FILE* out)
{
bool first = true;
- for (size_t i = 0; i < m_nodes.size(); ++i) {
- if (m_nodes[i].isClear())
+ for (size_t i = 0; i < m_block->size(); ++i) {
+ NodeIndex index = m_block->at(i);
+ AbstractValue& value = m_nodes[index];
+ if (value.isClear())
continue;
if (first)
first = false;
else
fprintf(out, " ");
- fprintf(out, "@%lu:", static_cast<unsigned long>(i + m_block->begin));
- m_nodes[i].dump(out);
+ fprintf(out, "@%lu:", static_cast<unsigned long>(index));
+ value.dump(out);
}
}
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index 256e7495f..d9d5cc0f8 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -98,7 +98,7 @@ public:
AbstractValue& forNode(NodeIndex nodeIndex)
{
- return m_nodes[nodeIndex - m_block->begin];
+ return m_nodes[nodeIndex];
}
AbstractValue& forNode(NodeUse nodeUse)
@@ -152,7 +152,7 @@ public:
// if execution should continue past this node. Notably, it will return true
// for block terminals, so long as those terminals are not Return or variants
// of Throw.
- bool execute(NodeIndex);
+ bool execute(unsigned);
// Is the execution state still valid? This will be false if execute() has
// returned false previously.
@@ -163,20 +163,20 @@ public:
// that block must be abstractly interpreted again. This also sets
// to->cfaShouldRevisit to true, if it returns true, or if to has not been
// visited yet.
- static bool merge(BasicBlock* from, BasicBlock* to);
+ bool merge(BasicBlock* from, BasicBlock* to);
// Merge the abstract state stored at the block's tail into all of its
// successors. Returns true if any of the successors' states changed. Note
// that this is automatically called in endBasicBlock() if MergeMode is
// MergeToSuccessors.
- static bool mergeToSuccessors(Graph&, BasicBlock*);
+ bool mergeToSuccessors(Graph&, BasicBlock*);
#ifndef NDEBUG
void dump(FILE* out);
#endif
private:
- void clobberStructures(NodeIndex);
+ void clobberStructures(unsigned);
bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex);
@@ -185,7 +185,7 @@ private:
CodeBlock* m_codeBlock;
Graph& m_graph;
- Vector<AbstractValue, 32> m_nodes;
+ Vector<AbstractValue, 64> m_nodes;
Operands<AbstractValue> m_variables;
BasicBlock* m_block;
bool m_haveStructures;
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index aa5518187..682c7a90f 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -442,6 +442,11 @@ struct AbstractValue {
if (mergePredictions(m_type, predictionFromValue(value)) != m_type)
return false;
+ if (value.isEmpty()) {
+ ASSERT(m_type & PredictEmpty);
+ return true;
+ }
+
if (m_structure.isTop())
return true;
diff --git a/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp b/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
index f55533a61..9a49364dd 100644
--- a/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
@@ -80,11 +80,8 @@ private:
if (!node.shouldGenerate())
return;
- NodeType op = node.op;
- ArithNodeFlags flags = 0;
-
- if (node.hasArithNodeFlags())
- flags = node.rawArithNodeFlags();
+ NodeType op = static_cast<NodeType>(node.op);
+ NodeFlags flags = node.flags;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
@@ -131,6 +128,11 @@ private:
break;
}
+ case ArithNegate: {
+ changed |= m_graph[node.child1()].mergeArithNodeFlags(flags);
+ break;
+ }
+
case ArithMul:
case ArithDiv: {
// As soon as a multiply happens, we can easily end up in the part
@@ -173,7 +175,7 @@ private:
default:
flags |= NodeUsedAsNumber | NodeNeedsNegZero;
- if (op & NodeHasVarArgs) {
+ if (node.flags & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeArithNodeFlags(flags);
} else {
@@ -217,6 +219,9 @@ private:
NodeIndex m_compileIndex;
bool m_changed;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ unsigned m_count;
+#endif
};
void performArithNodeFlagsInference(Graph& graph)
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
index 9d464bdc2..1c890b498 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
@@ -38,11 +38,9 @@ namespace JSC { namespace DFG {
typedef Vector <BlockIndex, 2> PredecessorList;
-struct BasicBlock {
- BasicBlock(unsigned bytecodeBegin, NodeIndex begin, unsigned numArguments, unsigned numLocals)
+struct BasicBlock : Vector<NodeIndex, 8> {
+ BasicBlock(unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals)
: bytecodeBegin(bytecodeBegin)
- , begin(begin)
- , end(NoNode)
, isOSRTarget(false)
, cfaHasVisited(false)
, cfaShouldRevisit(false)
@@ -69,8 +67,6 @@ struct BasicBlock {
// for other purposes due to inlining.
unsigned bytecodeBegin;
- NodeIndex begin;
- NodeIndex end;
bool isOSRTarget;
bool cfaHasVisited;
bool cfaShouldRevisit;
@@ -79,6 +75,7 @@ struct BasicBlock {
#endif
bool isReachable;
+ Vector<NodeIndex> phis;
PredecessorList m_predecessors;
Operands<NodeIndex, NodeIndexTraits> variablesAtHead;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeCache.h b/Source/JavaScriptCore/dfg/DFGByteCodeCache.h
index fd3b5147f..f6a745c66 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeCache.h
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeCache.h
@@ -138,7 +138,6 @@ public:
delete iter->second.codeBlock;
continue;
}
- iter->second.codeBlock->m_shouldDiscardBytecode = iter->second.oldValueOfShouldDiscardBytecode;
}
}
@@ -155,7 +154,6 @@ public:
value.codeBlock = key.executable()->codeBlockWithBytecodeFor(key.kind());
if (value.codeBlock) {
value.owned = false;
- value.oldValueOfShouldDiscardBytecode = value.codeBlock->m_shouldDiscardBytecode;
} else {
// Nope, so try to parse one.
JSObject* exception;
@@ -171,13 +169,6 @@ public:
value.codeBlock = 0;
}
- // If we're about to return a code block, make sure that we're not going
- // to be discarding its bytecode if a GC were to happen during DFG
- // compilation. That's unlikely, but it's good to thoroughly enjoy this
- // kind of paranoia.
- if (!!value.codeBlock)
- value.codeBlock->m_shouldDiscardBytecode = false;
-
m_map.add(key, value);
return value.codeBlock;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 0e575db4e..3a3678d12 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -66,6 +66,7 @@ public:
, m_globalResolveNumber(0)
, m_inlineStackTop(0)
, m_haveBuiltOperandMaps(false)
+ , m_emptyJSValueIndex(UINT_MAX)
{
ASSERT(m_profiledBlock);
@@ -185,16 +186,32 @@ private:
// Two possibilities: either the block wants the local to be live
// but has not loaded its value, or it has loaded its value, in
// which case we're done.
- Node& flushChild = m_graph[nodePtr->child1()];
+ nodeIndex = nodePtr->child1().index();
+ Node& flushChild = m_graph[nodeIndex];
if (flushChild.op == Phi) {
VariableAccessData* variableAccessData = flushChild.variableAccessData();
- nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodePtr->child1().index()));
+ nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex));
m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
return nodeIndex;
}
nodePtr = &flushChild;
}
+
+ ASSERT(&m_graph[nodeIndex] == nodePtr);
ASSERT(nodePtr->op != Flush);
+
+ if (m_graph.localIsCaptured(operand)) {
+ // We wish to use the same variable access data as the previous access,
+ // but for all other purposes we want to issue a load since for all we
+ // know, at this stage of compilation, the local has been clobbered.
+
+ // Make sure we link to the Phi node, not to the GetLocal.
+ if (nodePtr->op == GetLocal)
+ nodeIndex = nodePtr->child1().index();
+
+ return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex));
+ }
+
if (nodePtr->op == GetLocal)
return nodeIndex;
ASSERT(nodePtr->op == SetLocal);
@@ -218,7 +235,11 @@ private:
}
void setLocal(unsigned operand, NodeIndex value)
{
- m_currentBlock->variablesAtTail.local(operand) = addToGraph(SetLocal, OpInfo(newVariableAccessData(operand)), value);
+ VariableAccessData* variableAccessData = newVariableAccessData(operand);
+ NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
+ m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
+ if (m_graph.localIsCaptured(operand))
+ addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
// Used in implementing get/set, above, where the operand is an argument.
@@ -226,7 +247,7 @@ private:
{
unsigned argument = operandToArgument(operand);
ASSERT(argument < m_numArguments);
-
+
NodeIndex nodeIndex = m_currentBlock->variablesAtTail.argument(argument);
if (nodeIndex != NoNode) {
@@ -235,16 +256,18 @@ private:
// Two possibilities: either the block wants the local to be live
// but has not loaded its value, or it has loaded its value, in
// which case we're done.
- Node& flushChild = m_graph[nodePtr->child1()];
+ nodeIndex = nodePtr->child1().index();
+ Node& flushChild = m_graph[nodeIndex];
if (flushChild.op == Phi) {
VariableAccessData* variableAccessData = flushChild.variableAccessData();
- nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodePtr->child1().index()));
+ nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex));
m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
return nodeIndex;
}
nodePtr = &flushChild;
}
+ ASSERT(&m_graph[nodeIndex] == nodePtr);
ASSERT(nodePtr->op != Flush);
if (nodePtr->op == SetArgument) {
@@ -256,6 +279,12 @@ private:
return nodeIndex;
}
+ if (m_graph.argumentIsCaptured(argument)) {
+ if (nodePtr->op == GetLocal)
+ nodeIndex = nodePtr->child1().index();
+ return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex));
+ }
+
if (nodePtr->op == GetLocal)
return nodeIndex;
@@ -278,11 +307,15 @@ private:
{
unsigned argument = operandToArgument(operand);
ASSERT(argument < m_numArguments);
-
- m_currentBlock->variablesAtTail.argument(argument) = addToGraph(SetLocal, OpInfo(newVariableAccessData(operand)), value);
+
+ VariableAccessData* variableAccessData = newVariableAccessData(operand);
+ NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
+ m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
+ if (m_graph.argumentIsCaptured(argument))
+ addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
- void flush(int operand)
+ void flushArgument(int operand)
{
// FIXME: This should check if the same operand had already been flushed to
// some other local variable.
@@ -308,7 +341,10 @@ private:
nodeIndex = node.child1().index();
ASSERT(m_graph[nodeIndex].op != Flush);
-
+
+ // Emit a Flush regardless of whether we already flushed it.
+ // This gives us guidance to see that the variable also needs to be flushed
+ // for arguments, even if it already had to be flushed for other reasons.
addToGraph(Flush, OpInfo(node.variableAccessData()), nodeIndex);
return;
}
@@ -533,8 +569,10 @@ private:
{
NodeIndex resultIndex = (NodeIndex)m_graph.size();
m_graph.append(Node(op, currentCodeOrigin(), child1, child2, child3));
+ ASSERT(op != Phi);
+ m_currentBlock->append(resultIndex);
- if (op & NodeMustGenerate)
+ if (defaultFlags(op) & NodeMustGenerate)
m_graph.ref(resultIndex);
return resultIndex;
}
@@ -542,8 +580,12 @@ private:
{
NodeIndex resultIndex = (NodeIndex)m_graph.size();
m_graph.append(Node(op, currentCodeOrigin(), info, child1, child2, child3));
+ if (op == Phi)
+ m_currentBlock->phis.append(resultIndex);
+ else
+ m_currentBlock->append(resultIndex);
- if (op & NodeMustGenerate)
+ if (defaultFlags(op) & NodeMustGenerate)
m_graph.ref(resultIndex);
return resultIndex;
}
@@ -551,8 +593,10 @@ private:
{
NodeIndex resultIndex = (NodeIndex)m_graph.size();
m_graph.append(Node(op, currentCodeOrigin(), info1, info2, child1, child2, child3));
+ ASSERT(op != Phi);
+ m_currentBlock->append(resultIndex);
- if (op & NodeMustGenerate)
+ if (defaultFlags(op) & NodeMustGenerate)
m_graph.ref(resultIndex);
return resultIndex;
}
@@ -561,13 +605,25 @@ private:
{
NodeIndex resultIndex = (NodeIndex)m_graph.size();
m_graph.append(Node(Node::VarArg, op, currentCodeOrigin(), info1, info2, m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs));
+ ASSERT(op != Phi);
+ m_currentBlock->append(resultIndex);
m_numPassedVarArgs = 0;
- if (op & NodeMustGenerate)
+ if (defaultFlags(op) & NodeMustGenerate)
m_graph.ref(resultIndex);
return resultIndex;
}
+
+ NodeIndex insertPhiNode(OpInfo info, BasicBlock* block)
+ {
+ NodeIndex resultIndex = (NodeIndex)m_graph.size();
+ m_graph.append(Node(Phi, currentCodeOrigin(), info));
+ block->phis.append(resultIndex);
+
+ return resultIndex;
+ }
+
void addVarArgChild(NodeIndex child)
{
m_graph.m_varArgChildren.append(NodeUse(child));
@@ -643,13 +699,14 @@ private:
return nodeIndex;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Making %s @%u safe at bc#%u because slow-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(m_graph[nodeIndex].op), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
+ dataLog("Making %s @%u safe at bc#%u because slow-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(static_cast<NodeType>(m_graph[nodeIndex].op)), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
#endif
switch (m_graph[nodeIndex].op) {
case UInt32ToNumber:
case ArithAdd:
case ArithSub:
+ case ArithNegate:
case ValueAdd:
case ArithMod: // for ArithMode "MayOverflow" means we tried to divide by zero, or we saw double.
m_graph[nodeIndex].mergeArithNodeFlags(NodeMayOverflow);
@@ -695,7 +752,7 @@ private:
return nodeIndex;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Making %s @%u safe at bc#%u because special fast-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(m_graph[nodeIndex].op), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->specialFastCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
+ dataLog("Making %s @%u safe at bc#%u because special fast-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(static_cast<NodeType>(m_graph[nodeIndex].op)), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->specialFastCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
#endif
// FIXME: It might be possible to make this more granular. The DFG certainly can
@@ -912,6 +969,9 @@ private:
IdentifierMap m_identifierMap;
// Mapping between values and constant numbers.
JSValueMap m_jsValueMap;
+ // Index of the empty value, or UINT_MAX if there is no mapping. This is a horrible
+ // work-around for the fact that JSValueMap can't handle "empty" values.
+ unsigned m_emptyJSValueIndex;
// Cache of code blocks that we've generated bytecode for.
ByteCodeCache<canInlineFunctionFor> m_codeBlockCache;
@@ -1066,7 +1126,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// FIXME: Don't flush constants!
for (int i = 1; i < argumentCountIncludingThis; ++i)
- flush(registerOffset + argumentToOperand(i));
+ flushArgument(registerOffset + argumentToOperand(i));
int inlineCallFrameStart = m_inlineStackTop->remapOperand(registerOffset) - RegisterFile::CallFrameHeaderSize;
@@ -1129,7 +1189,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// the caller to continue in whatever basic block we're in right now.
if (!inlineStackEntry.m_didEarlyReturn && inlineStackEntry.m_didReturn) {
BasicBlock* lastBlock = m_graph.m_blocks.last().get();
- ASSERT(lastBlock->begin == lastBlock->end || !m_graph.last().isTerminal());
+ ASSERT(lastBlock->isEmpty() || !m_graph.last().isTerminal());
// If we created new blocks then the last block needs linking, but in the
// caller. It doesn't need to be linked to, but it needs outgoing links.
@@ -1161,7 +1221,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
continue;
BasicBlock* block = m_graph.m_blocks[inlineStackEntry.m_unlinkedBlocks[i].m_blockIndex].get();
ASSERT(!block->isLinked);
- Node& node = m_graph[block->end - 1];
+ Node& node = m_graph[block->last()];
ASSERT(node.op == Jump);
ASSERT(node.takenBlockIndex() == NoBlock);
node.setTakenBlockIndex(m_graph.m_blocks.size());
@@ -1172,7 +1232,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
}
// Need to create a new basic block for the continuation at the caller.
- OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(nextOffset, m_graph.size(), m_numArguments, m_numLocals));
+ OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(nextOffset, m_numArguments, m_numLocals));
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("Creating inline epilogue basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
#endif
@@ -1207,7 +1267,7 @@ bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType o
}
if (argumentCountIncludingThis == 3) { // Math.min(x, y)
- set(resultOperand, addToGraph(op, OpInfo(NodeUseBottom), get(registerOffset + argumentToOperand(1)), get(registerOffset + argumentToOperand(2))));
+ set(resultOperand, addToGraph(op, get(registerOffset + argumentToOperand(1)), get(registerOffset + argumentToOperand(2))));
return true;
}
@@ -1235,7 +1295,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
if (!MacroAssembler::supportsFloatingPointAbs())
return false;
- NodeIndex nodeIndex = addToGraph(ArithAbs, OpInfo(NodeUseBottom), get(registerOffset + argumentToOperand(1)));
+ NodeIndex nodeIndex = addToGraph(ArithAbs, get(registerOffset + argumentToOperand(1)));
if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
m_graph[nodeIndex].mergeArithNodeFlags(NodeMayOverflow);
set(resultOperand, nodeIndex);
@@ -1364,7 +1424,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
// logic relies on every bytecode resulting in one or more nodes, which would
// be true anyway except for op_loop_hint, which emits a Phantom to force this
// to be true.
- if (m_currentBlock->begin != m_graph.size())
+ if (!m_currentBlock->isEmpty())
addToGraph(Jump, OpInfo(m_currentIndex));
else {
#if DFG_ENABLE(DEBUG_VERBOSE)
@@ -1502,11 +1562,11 @@ bool ByteCodeParser::parseBlock(unsigned limit)
if (valueOfInt32Constant(op2) & 0x1f)
result = addToGraph(BitURShift, op1, op2);
else
- result = makeSafe(addToGraph(UInt32ToNumber, OpInfo(NodeUseBottom), op1));
+ result = makeSafe(addToGraph(UInt32ToNumber, op1));
} else {
// Cannot optimize at this stage; shift & potentially rebox as a double.
result = addToGraph(BitURShift, op1, op2);
- result = makeSafe(addToGraph(UInt32ToNumber, OpInfo(NodeUseBottom), result));
+ result = makeSafe(addToGraph(UInt32ToNumber, result));
}
set(currentInstruction[1].u.operand, result);
NEXT_OPCODE(op_urshift);
@@ -1517,7 +1577,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_pre_inc: {
unsigned srcDst = currentInstruction[1].u.operand;
NodeIndex op = get(srcDst);
- set(srcDst, makeSafe(addToGraph(ArithAdd, OpInfo(NodeUseBottom), op, one())));
+ set(srcDst, makeSafe(addToGraph(ArithAdd, op, one())));
NEXT_OPCODE(op_pre_inc);
}
@@ -1527,14 +1587,14 @@ bool ByteCodeParser::parseBlock(unsigned limit)
ASSERT(result != srcDst); // Required for assumptions we make during OSR.
NodeIndex op = get(srcDst);
set(result, op);
- set(srcDst, makeSafe(addToGraph(ArithAdd, OpInfo(NodeUseBottom), op, one())));
+ set(srcDst, makeSafe(addToGraph(ArithAdd, op, one())));
NEXT_OPCODE(op_post_inc);
}
case op_pre_dec: {
unsigned srcDst = currentInstruction[1].u.operand;
NodeIndex op = get(srcDst);
- set(srcDst, makeSafe(addToGraph(ArithSub, OpInfo(NodeUseBottom), op, one())));
+ set(srcDst, makeSafe(addToGraph(ArithSub, op, one())));
NEXT_OPCODE(op_pre_dec);
}
@@ -1543,7 +1603,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
unsigned srcDst = currentInstruction[2].u.operand;
NodeIndex op = get(srcDst);
set(result, op);
- set(srcDst, makeSafe(addToGraph(ArithSub, OpInfo(NodeUseBottom), op, one())));
+ set(srcDst, makeSafe(addToGraph(ArithSub, op, one())));
NEXT_OPCODE(op_post_dec);
}
@@ -1553,38 +1613,44 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
if (m_graph[op1].hasNumberResult() && m_graph[op2].hasNumberResult())
- set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithAdd, OpInfo(NodeUseBottom), op1, op2)));
+ set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithAdd, op1, op2)));
else
- set(currentInstruction[1].u.operand, makeSafe(addToGraph(ValueAdd, OpInfo(NodeUseBottom), op1, op2)));
+ set(currentInstruction[1].u.operand, makeSafe(addToGraph(ValueAdd, op1, op2)));
NEXT_OPCODE(op_add);
}
case op_sub: {
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
- set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithSub, OpInfo(NodeUseBottom), op1, op2)));
+ set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithSub, op1, op2)));
NEXT_OPCODE(op_sub);
}
+ case op_negate: {
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithNegate, op1)));
+ NEXT_OPCODE(op_negate);
+ }
+
case op_mul: {
// Multiply requires that the inputs are not truncated, unfortunately.
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
- set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMul, OpInfo(NodeUseBottom), op1, op2)));
+ set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMul, op1, op2)));
NEXT_OPCODE(op_mul);
}
case op_mod: {
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
- set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMod, OpInfo(NodeUseBottom), op1, op2)));
+ set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMod, op1, op2)));
NEXT_OPCODE(op_mod);
}
case op_div: {
NodeIndex op1 = get(currentInstruction[2].u.operand);
NodeIndex op2 = get(currentInstruction[3].u.operand);
- set(currentInstruction[1].u.operand, makeDivSafe(addToGraph(ArithDiv, OpInfo(NodeUseBottom), op1, op2)));
+ set(currentInstruction[1].u.operand, makeDivSafe(addToGraph(ArithDiv, op1, op2)));
NEXT_OPCODE(op_div);
}
@@ -2187,6 +2253,42 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NEXT_OPCODE(op_loop_hint);
}
+
+ case op_init_lazy_reg: {
+ set(currentInstruction[1].u.operand, getJSConstantForValue(JSValue()));
+ NEXT_OPCODE(op_init_lazy_reg);
+ }
+
+ case op_create_activation: {
+ set(currentInstruction[1].u.operand, addToGraph(CreateActivation, get(currentInstruction[1].u.operand)));
+ NEXT_OPCODE(op_create_activation);
+ }
+
+ case op_tear_off_activation: {
+ // This currently ignores arguments because we don't support them yet.
+ addToGraph(TearOffActivation, get(currentInstruction[1].u.operand));
+ NEXT_OPCODE(op_tear_off_activation);
+ }
+
+ case op_new_func: {
+ if (!currentInstruction[3].u.operand) {
+ set(currentInstruction[1].u.operand,
+ addToGraph(NewFunctionNoCheck, OpInfo(currentInstruction[2].u.operand)));
+ } else {
+ set(currentInstruction[1].u.operand,
+ addToGraph(
+ NewFunction,
+ OpInfo(currentInstruction[2].u.operand),
+ get(currentInstruction[1].u.operand)));
+ }
+ NEXT_OPCODE(op_new_func);
+ }
+
+ case op_new_func_exp: {
+ set(currentInstruction[1].u.operand,
+ addToGraph(NewFunctionExpression, OpInfo(currentInstruction[2].u.operand)));
+ NEXT_OPCODE(op_new_func_exp);
+ }
default:
// Parse failed! This should not happen because the capabilities checker
@@ -2231,7 +2333,7 @@ void ByteCodeParser::processPhiStack()
dataLog(" Did not find node, adding phi.\n");
#endif
- valueInPredecessor = addToGraph(Phi, OpInfo(newVariableAccessData(stackType == ArgumentPhiStack ? argumentToOperand(varNo) : static_cast<int>(varNo))));
+ valueInPredecessor = insertPhiNode(OpInfo(newVariableAccessData(stackType == ArgumentPhiStack ? argumentToOperand(varNo) : static_cast<int>(varNo))), predecessorBlock);
var = valueInPredecessor;
if (stackType == ArgumentPhiStack)
predecessorBlock->variablesAtHead.setArgumentFirstTime(varNo, valueInPredecessor);
@@ -2255,7 +2357,11 @@ void ByteCodeParser::processPhiStack()
dataLog(" Found @%u.\n", valueInPredecessor);
#endif
}
- ASSERT(m_graph[valueInPredecessor].op == SetLocal || m_graph[valueInPredecessor].op == Phi || m_graph[valueInPredecessor].op == Flush || (m_graph[valueInPredecessor].op == SetArgument && stackType == ArgumentPhiStack));
+ ASSERT(m_graph[valueInPredecessor].op == SetLocal
+ || m_graph[valueInPredecessor].op == Phi
+ || m_graph[valueInPredecessor].op == Flush
+ || (m_graph[valueInPredecessor].op == SetArgument
+ && stackType == ArgumentPhiStack));
VariableAccessData* dataForPredecessor = m_graph[valueInPredecessor].variableAccessData();
@@ -2309,7 +2415,7 @@ void ByteCodeParser::processPhiStack()
continue;
}
- NodeIndex newPhi = addToGraph(Phi, OpInfo(dataForPhi));
+ NodeIndex newPhi = insertPhiNode(OpInfo(dataForPhi), entry.m_block);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Splitting @%u, created @%u.\n", entry.m_phi, newPhi);
@@ -2349,10 +2455,9 @@ void ByteCodeParser::fixVariableAccessPredictions()
void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BlockIndex>& possibleTargets)
{
- ASSERT(block->end != NoNode);
ASSERT(!block->isLinked);
- ASSERT(block->end > block->begin);
- Node& node = m_graph[block->end - 1];
+ ASSERT(!block->isEmpty());
+ Node& node = m_graph[block->last()];
ASSERT(node.isTerminal());
switch (node.op) {
@@ -2416,7 +2521,7 @@ void ByteCodeParser::determineReachability()
BasicBlock* block = m_graph.m_blocks[index].get();
ASSERT(block->isLinked);
- Node& node = m_graph[block->end - 1];
+ Node& node = m_graph[block->last()];
ASSERT(node.isTerminal());
if (node.isJump())
@@ -2435,8 +2540,13 @@ void ByteCodeParser::buildOperandMapsIfNecessary()
for (size_t i = 0; i < m_codeBlock->numberOfIdentifiers(); ++i)
m_identifierMap.add(m_codeBlock->identifier(i).impl(), i);
- for (size_t i = 0; i < m_codeBlock->numberOfConstantRegisters(); ++i)
- m_jsValueMap.add(JSValue::encode(m_codeBlock->getConstant(i + FirstConstantRegisterIndex)), i + FirstConstantRegisterIndex);
+ for (size_t i = 0; i < m_codeBlock->numberOfConstantRegisters(); ++i) {
+ JSValue value = m_codeBlock->getConstant(i + FirstConstantRegisterIndex);
+ if (!value)
+ m_emptyJSValueIndex = i + FirstConstantRegisterIndex;
+ else
+ m_jsValueMap.add(JSValue::encode(value), i + FirstConstantRegisterIndex);
+ }
m_haveBuiltOperandMaps = true;
}
@@ -2486,6 +2596,15 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(ByteCodeParser* byteCodeParse
}
for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i) {
JSValue value = codeBlock->getConstant(i + FirstConstantRegisterIndex);
+ if (!value) {
+ if (byteCodeParser->m_emptyJSValueIndex == UINT_MAX) {
+ byteCodeParser->m_emptyJSValueIndex = byteCodeParser->m_codeBlock->numberOfConstantRegisters() + FirstConstantRegisterIndex;
+ byteCodeParser->m_codeBlock->addConstant(JSValue());
+ byteCodeParser->m_constants.append(ConstantRecord());
+ }
+ m_constantRemap[i] = byteCodeParser->m_emptyJSValueIndex;
+ continue;
+ }
pair<JSValueMap::iterator, bool> result = byteCodeParser->m_jsValueMap.add(JSValue::encode(value), byteCodeParser->m_codeBlock->numberOfConstantRegisters() + FirstConstantRegisterIndex);
if (result.second) {
byteCodeParser->m_codeBlock->addConstant(value);
@@ -2527,6 +2646,16 @@ void ByteCodeParser::parseCodeBlock()
{
CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ dataLog("Parsing code block %p. codeType = %s, numCapturedVars = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n",
+ codeBlock,
+ codeTypeToString(codeBlock->codeType()),
+ codeBlock->m_numCapturedVars,
+ codeBlock->needsFullScopeChain()?"true":"false",
+ codeBlock->ownerExecutable()->needsActivation()?"true":"false",
+ codeBlock->ownerExecutable()->isStrictMode()?"true":"false");
+#endif
+
for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= codeBlock->numberOfJumpTargets(); ++jumpTargetIndex) {
// The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions.
unsigned limit = jumpTargetIndex < codeBlock->numberOfJumpTargets() ? codeBlock->jumpTarget(jumpTargetIndex) : codeBlock->instructions().size();
@@ -2539,7 +2668,7 @@ void ByteCodeParser::parseCodeBlock()
do {
if (!m_currentBlock) {
// Check if we can use the last block.
- if (!m_graph.m_blocks.isEmpty() && m_graph.m_blocks.last()->begin == m_graph.m_blocks.last()->end) {
+ if (!m_graph.m_blocks.isEmpty() && m_graph.m_blocks.last()->isEmpty()) {
// This must be a block belonging to us.
ASSERT(m_inlineStackTop->m_unlinkedBlocks.last().m_blockIndex == m_graph.m_blocks.size() - 1);
// Either the block is linkable or it isn't. If it's linkable then it's the last
@@ -2557,7 +2686,7 @@ void ByteCodeParser::parseCodeBlock()
#endif
m_currentBlock->bytecodeBegin = m_currentIndex;
} else {
- OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_graph.size(), m_numArguments, m_numLocals));
+ OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_numArguments, m_numLocals));
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("Creating basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame));
#endif
@@ -2580,10 +2709,8 @@ void ByteCodeParser::parseCodeBlock()
// are at the end of an inline function, or we realized that we
// should stop parsing because there was a return in the first
// basic block.
- ASSERT(m_currentBlock->begin == m_graph.size() || m_graph.last().isTerminal() || (m_currentIndex == codeBlock->instructions().size() && m_inlineStackTop->m_inlineCallFrame) || !shouldContinueParsing);
+ ASSERT(m_currentBlock->isEmpty() || m_graph.last().isTerminal() || (m_currentIndex == codeBlock->instructions().size() && m_inlineStackTop->m_inlineCallFrame) || !shouldContinueParsing);
- m_currentBlock->end = m_graph.size();
-
if (!shouldContinueParsing)
return;
@@ -2600,6 +2727,11 @@ bool ByteCodeParser::parse()
// Set during construction.
ASSERT(!m_currentIndex);
+#if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
+ // We should be pretending that the code has an activation.
+ ASSERT(m_graph.needsActivation());
+#endif
+
InlineStackEntry inlineStackEntry(this, m_codeBlock, m_profiledBlock, NoBlock, InvalidVirtualRegister, 0, InvalidVirtualRegister, InvalidVirtualRegister, CodeForCall);
parseCodeBlock();
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index 3481f99e8..16793bb46 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -420,6 +420,13 @@ public:
move(arg2, GPRInfo::argumentGPR2);
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
}
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, ImmPtr arg2)
+ {
+ move(arg1, GPRInfo::argumentGPR1);
+ move(arg2, GPRInfo::argumentGPR2);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2)
{
@@ -427,6 +434,13 @@ public:
move(arg1, GPRInfo::argumentGPR1);
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
}
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(ImmPtr arg1, GPRReg arg2)
+ {
+ move(arg2, GPRInfo::argumentGPR2); // Move this first, so setting arg1 does not trample!
+ move(arg1, GPRInfo::argumentGPR1);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2)
{
diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
index ac1e26c19..b4e75f808 100644
--- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
@@ -82,15 +82,16 @@ private:
dumpOperands(block->valuesAtHead, WTF::dataFile());
dataLog("\n");
#endif
- for (NodeIndex nodeIndex = block->begin; nodeIndex < block->end; ++nodeIndex) {
+ for (unsigned i = 0; i < block->size(); ++i) {
+ NodeIndex nodeIndex = block->at(i);
if (!m_graph[nodeIndex].shouldGenerate())
continue;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: ", Graph::opName(m_graph[nodeIndex].op), nodeIndex);
+ dataLog(" %s @%u: ", Graph::opName(static_cast<NodeType>(m_graph[nodeIndex].op)), nodeIndex);
m_state.dump(WTF::dataFile());
dataLog("\n");
#endif
- if (!m_state.execute(nodeIndex))
+ if (!m_state.execute(i))
break;
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
@@ -120,6 +121,9 @@ private:
AbstractState m_state;
bool m_changed;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ unsigned m_count;
+#endif
};
void performCFA(Graph& graph)
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index a3c27ebc1..82e1b4609 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -43,9 +43,6 @@ public:
for (unsigned i = 0; i < m_graph.size(); ++i)
m_replacements[i] = NoNode;
-
- for (unsigned i = 0; i < LastNodeId; ++i)
- m_lastSeen[i] = NoNode;
}
void run()
@@ -71,68 +68,14 @@ private:
return canonicalize(nodeUse.indexUnchecked());
}
- // Computes where the search for a candidate for CSE should start. Don't call
- // this directly; call startIndex() instead as it does logging in debug mode.
- NodeIndex computeStartIndexForChildren(NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ unsigned endIndexForPureCSE()
{
- const unsigned limit = 300;
-
- NodeIndex start = m_start;
- if (m_compileIndex - start > limit)
- start = m_compileIndex - limit;
-
- ASSERT(start >= m_start);
-
- NodeIndex child = canonicalize(child1);
- if (child == NoNode)
- return start;
-
- if (start < child)
- start = child;
-
- child = canonicalize(child2);
- if (child == NoNode)
- return start;
-
- if (start < child)
- start = child;
-
- child = canonicalize(child3);
- if (child == NoNode)
- return start;
-
- if (start < child)
- start = child;
-
- return start;
- }
-
- NodeIndex startIndexForChildren(NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
- {
- NodeIndex result = computeStartIndexForChildren(child1, child2, child3);
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" lookback %u: ", result);
-#endif
- return result;
- }
-
- NodeIndex startIndex()
- {
- Node& node = m_graph[m_compileIndex];
- return startIndexForChildren(
- node.child1().indexUnchecked(),
- node.child2().indexUnchecked(),
- node.child3().indexUnchecked());
- }
-
- NodeIndex endIndexForPureCSE()
- {
- NodeIndex result = m_lastSeen[m_graph[m_compileIndex].op & NodeIdMask];
- if (result == NoNode)
+ unsigned result = m_lastSeen[m_graph[m_compileIndex].op];
+ if (result == UINT_MAX)
result = 0;
else
result++;
- ASSERT(result <= m_compileIndex);
+ ASSERT(result <= m_indexInBlock);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" limit %u: ", result);
#endif
@@ -145,13 +88,16 @@ private:
NodeIndex child2 = canonicalize(node.child2());
NodeIndex child3 = canonicalize(node.child3());
- NodeIndex start = startIndex();
- for (NodeIndex index = endIndexForPureCSE(); index-- > start;) {
+ for (unsigned i = endIndexForPureCSE(); i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1 || index == child2 || index == child3)
+ break;
+
Node& otherNode = m_graph[index];
if (node.op != otherNode.op)
continue;
- if (node.arithNodeFlagsForCompare() != otherNode.arithNodeFlagsForCompare())
+ if (node.arithNodeFlags() != otherNode.arithNodeFlags())
continue;
NodeIndex otherChild = canonicalize(otherNode.child1());
@@ -201,9 +147,9 @@ private:
bool clobbersWorld(NodeIndex nodeIndex)
{
Node& node = m_graph[nodeIndex];
- if (node.op & NodeClobbersWorld)
+ if (node.flags & NodeClobbersWorld)
return true;
- if (!(node.op & NodeMightClobber))
+ if (!(node.flags & NodeMightClobber))
return false;
switch (node.op) {
case ValueAdd:
@@ -229,11 +175,14 @@ private:
NodeIndex child2 = canonicalize(node.child2());
NodeIndex child3 = canonicalize(node.child3());
- NodeIndex start = startIndex();
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1 || index == child2 || index == child3)
+ break;
+
Node& otherNode = m_graph[index];
if (node.op == otherNode.op
- && node.arithNodeFlagsForCompare() == otherNode.arithNodeFlagsForCompare()) {
+ && node.arithNodeFlags() == otherNode.arithNodeFlags()) {
NodeIndex otherChild = canonicalize(otherNode.child1());
if (otherChild == NoNode)
return index;
@@ -258,8 +207,8 @@ private:
NodeIndex globalVarLoadElimination(unsigned varNumber, JSGlobalObject* globalObject)
{
- NodeIndex start = startIndexForChildren();
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
Node& node = m_graph[index];
switch (node.op) {
case GetGlobalVar:
@@ -281,8 +230,11 @@ private:
NodeIndex getByValLoadElimination(NodeIndex child1, NodeIndex child2)
{
- NodeIndex start = startIndexForChildren(child1, child2);
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1 || index == canonicalize(child2))
+ break;
+
Node& node = m_graph[index];
switch (node.op) {
case GetByVal:
@@ -322,8 +274,11 @@ private:
bool checkFunctionElimination(JSFunction* function, NodeIndex child1)
{
- NodeIndex start = startIndexForChildren(child1);
- for (NodeIndex index = endIndexForPureCSE(); index-- > start;) {
+ for (unsigned i = endIndexForPureCSE(); i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1)
+ break;
+
Node& node = m_graph[index];
if (node.op == CheckFunction && node.child1() == child1 && node.function() == function)
return true;
@@ -333,8 +288,11 @@ private:
bool checkStructureLoadElimination(const StructureSet& structureSet, NodeIndex child1)
{
- NodeIndex start = startIndexForChildren(child1);
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1)
+ break;
+
Node& node = m_graph[index];
switch (node.op) {
case CheckStructure:
@@ -376,8 +334,11 @@ private:
NodeIndex getByOffsetLoadElimination(unsigned identifierNumber, NodeIndex child1)
{
- NodeIndex start = startIndexForChildren(child1);
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1)
+ break;
+
Node& node = m_graph[index];
switch (node.op) {
case GetByOffset:
@@ -419,8 +380,11 @@ private:
NodeIndex getPropertyStorageLoadElimination(NodeIndex child1)
{
- NodeIndex start = startIndexForChildren(child1);
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1)
+ break;
+
Node& node = m_graph[index];
switch (node.op) {
case GetPropertyStorage:
@@ -455,8 +419,11 @@ private:
NodeIndex getIndexedPropertyStorageLoadElimination(NodeIndex child1, bool hasIntegerIndexPrediction)
{
- NodeIndex start = startIndexForChildren(child1);
- for (NodeIndex index = m_compileIndex; index-- > start;) {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ if (index == child1)
+ break;
+
Node& node = m_graph[index];
switch (node.op) {
case GetIndexedPropertyStorage: {
@@ -493,8 +460,8 @@ private:
NodeIndex getScopeChainLoadElimination(unsigned depth)
{
- NodeIndex start = startIndexForChildren();
- for (NodeIndex index = endIndexForPureCSE(); index-- > start;) {
+ for (unsigned i = endIndexForPureCSE(); i--;) {
+ NodeIndex index = m_currentBlock->at(i);
Node& node = m_graph[index];
if (node.op == GetScopeChain
&& node.scopeChainDepth() == depth)
@@ -539,7 +506,7 @@ private:
#endif
Node& node = m_graph[m_compileIndex];
- node.op = Phantom;
+ node.setOpAndDefaultFlags(Phantom);
node.setRefCount(1);
// At this point we will eliminate all references to this node.
@@ -555,14 +522,14 @@ private:
Node& node = m_graph[m_compileIndex];
ASSERT(node.refCount() == 1);
ASSERT(node.mustGenerate());
- node.op = Phantom;
+ node.setOpAndDefaultFlags(Phantom);
}
void performNodeCSE(Node& node)
{
bool shouldGenerate = node.shouldGenerate();
- if (node.op & NodeHasVarArgs) {
+ if (node.flags & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
performSubstitution(m_graph.m_varArgChildren[childIdx], shouldGenerate);
} else {
@@ -575,7 +542,7 @@ private:
return;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: ", Graph::opName(m_graph[m_compileIndex].op), m_compileIndex);
+ dataLog(" %s @%u: ", Graph::opName(static_cast<NodeType>(m_graph[m_compileIndex].op)), m_compileIndex);
#endif
// NOTE: there are some nodes that we deliberately don't CSE even though we
@@ -598,6 +565,7 @@ private:
case BitURShift:
case ArithAdd:
case ArithSub:
+ case ArithNegate:
case ArithMul:
case ArithMod:
case ArithDiv:
@@ -701,7 +669,7 @@ private:
break;
}
- m_lastSeen[node.op & NodeIdMask] = m_compileIndex;
+ m_lastSeen[node.op] = m_indexInBlock;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog("\n");
#endif
@@ -709,16 +677,21 @@ private:
void performBlockCSE(BasicBlock& block)
{
- m_start = block.begin;
- NodeIndex end = block.end;
- for (m_compileIndex = m_start; m_compileIndex < end; ++m_compileIndex)
+ m_currentBlock = &block;
+ for (unsigned i = 0; i < LastNodeType; ++i)
+ m_lastSeen[i] = UINT_MAX;
+
+ for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
+ m_compileIndex = block[m_indexInBlock];
performNodeCSE(m_graph[m_compileIndex]);
+ }
}
- NodeIndex m_start;
+ BasicBlock* m_currentBlock;
NodeIndex m_compileIndex;
+ unsigned m_indexInBlock;
Vector<NodeIndex, 16> m_replacements;
- FixedArray<NodeIndex, LastNodeId> m_lastSeen;
+ FixedArray<unsigned, LastNodeType> m_lastSeen;
};
void performCSE(Graph& graph)
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h
index e339714e9..6509dbc3d 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.h
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h
@@ -57,11 +57,13 @@ inline bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
inline bool mightInlineFunctionForCall(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount
+ && !codeBlock->ownerExecutable()->needsActivation();
}
inline bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount
+ && !codeBlock->ownerExecutable()->needsActivation();
}
// Opcode checking.
@@ -84,6 +86,7 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
case op_post_dec:
case op_add:
case op_sub:
+ case op_negate:
case op_mul:
case op_mod:
case op_div:
@@ -151,21 +154,14 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
case op_throw_reference_error:
case op_call:
case op_construct:
- return true;
-
- // Opcodes we support conditionally. Enabling these opcodes currently results in
- // performance regressions. Each node that we disable under restrictions has a
- // comment describing what we know about the regression so far.
-
- // Regresses string-validate-input, probably because it uses comparisons (< and >)
- // on strings, which currently will cause speculation failures in some cases.
case op_new_regexp:
-#if DFG_ENABLE(RESTRICTIONS)
- return false;
-#else
+ case op_init_lazy_reg:
+ case op_create_activation:
+ case op_tear_off_activation:
+ case op_new_func:
+ case op_new_func_exp:
return true;
-#endif
-
+
default:
return false;
}
@@ -191,6 +187,14 @@ inline bool canInlineOpcode(OpcodeID opcodeID)
case op_new_regexp:
return false;
+ // We don't support inlining code that creates activations or has nested functions.
+ case op_init_lazy_reg:
+ case op_create_activation:
+ case op_tear_off_activation:
+ case op_new_func:
+ case op_new_func_exp:
+ return false;
+
default:
return canCompileOpcode(opcodeID);
}
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index 330504c3e..8ff1e5cdd 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -53,7 +53,7 @@
#define DFG_ENABLE_CONSISTENCY_CHECK 0
// Emit a breakpoint into the head of every generated function, to aid debugging in GDB.
#define DFG_ENABLE_JIT_BREAK_ON_EVERY_FUNCTION 0
-// Emit a breakpoint into the head of every generated node, to aid debugging in GDB.
+// Emit a breakpoint into the head of every generated block, to aid debugging in GDB.
#define DFG_ENABLE_JIT_BREAK_ON_EVERY_BLOCK 0
// Emit a breakpoint into the head of every generated node, to aid debugging in GDB.
#define DFG_ENABLE_JIT_BREAK_ON_EVERY_NODE 0
@@ -69,10 +69,11 @@
#define DFG_ENABLE_OSR_ENTRY ENABLE(DFG_JIT)
// Generate stats on how successful we were in making use of the DFG jit, and remaining on the hot path.
#define DFG_ENABLE_SUCCESS_STATS 0
-// Used to enable conditionally supported opcodes that currently result in performance regressions.
-#define DFG_ENABLE_RESTRICTIONS 1
// Enable verification that the DFG is able to insert code for control flow edges.
#define DFG_ENABLE_EDGE_CODE_VERIFICATION 0
+// Pretend that all variables in the top-level code block got captured. Great
+// for testing code gen for activations.
+#define DFG_ENABLE_ALL_VARIABLES_CAPTURED 0
namespace JSC { namespace DFG {
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index 124d7e637..a0af3e6ad 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -34,6 +34,7 @@
#include "DFGCSEPhase.h"
#include "DFGJITCompiler.h"
#include "DFGPredictionPropagationPhase.h"
+#include "DFGRedundantPhiEliminationPhase.h"
#include "DFGVirtualRegisterAllocationPhase.h"
namespace JSC { namespace DFG {
@@ -58,6 +59,7 @@ inline bool compile(CompileMode compileMode, JSGlobalData& globalData, CodeBlock
if (compileMode == CompileFunction)
dfg.predictArgumentTypes();
+ performRedundantPhiElimination(dfg);
performArithNodeFlagsInference(dfg);
performPredictionPropagation(dfg);
performCSE(dfg);
@@ -70,18 +72,19 @@ inline bool compile(CompileMode compileMode, JSGlobalData& globalData, CodeBlock
#endif
JITCompiler dataFlowJIT(dfg);
+ bool result;
if (compileMode == CompileFunction) {
ASSERT(jitCodeWithArityCheck);
- dataFlowJIT.compileFunction(jitCode, *jitCodeWithArityCheck);
+ result = dataFlowJIT.compileFunction(jitCode, *jitCodeWithArityCheck);
} else {
ASSERT(compileMode == CompileOther);
ASSERT(!jitCodeWithArityCheck);
- dataFlowJIT.compile(jitCode);
+ result = dataFlowJIT.compile(jitCode);
}
- return true;
+ return result;
}
bool tryCompile(JSGlobalData& globalData, CodeBlock* codeBlock, JITCode& jitCode)
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index b8eec93c7..900251e10 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -41,7 +41,7 @@ static const char* dfgOpNames[] = {
const char *Graph::opName(NodeType op)
{
- return dfgOpNames[op & NodeIdMask];
+ return dfgOpNames[op];
}
const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessData)
@@ -120,7 +120,7 @@ void Graph::dumpCodeOrigin(NodeIndex nodeIndex)
void Graph::dump(NodeIndex nodeIndex)
{
Node& node = at(nodeIndex);
- NodeType op = node.op;
+ NodeType op = static_cast<NodeType>(node.op);
unsigned refCount = node.refCount();
bool skipped = !refCount;
@@ -157,7 +157,7 @@ void Graph::dump(NodeIndex nodeIndex)
dataLog("-");
dataLog(">\t%s(", opName(op));
bool hasPrinted = false;
- if (op & NodeHasVarArgs) {
+ if (node.flags & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
if (hasPrinted)
dataLog(", ");
@@ -175,8 +175,8 @@ void Graph::dump(NodeIndex nodeIndex)
hasPrinted = !!node.child1();
}
- if (node.hasArithNodeFlags()) {
- dataLog("%s%s", hasPrinted ? ", " : "", arithNodeFlagsAsString(node.rawArithNodeFlags()));
+ if (node.arithNodeFlags()) {
+ dataLog("%s%s", hasPrinted ? ", " : "", arithNodeFlagsAsString(node.arithNodeFlags()));
hasPrinted = true;
}
if (node.hasVarNumber()) {
@@ -265,6 +265,12 @@ void Graph::dump()
for (size_t b = 0; b < m_blocks.size(); ++b) {
BasicBlock* block = m_blocks[b].get();
dataLog("Block #%u (bc#%u): %s%s\n", (int)b, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "");
+ dataLog(" Phi Nodes:\n");
+ for (size_t i = 0; i < block->phis.size(); ++i) {
+ // Dumping the dead Phi nodes is just annoying!
+ if (at(block->phis[i]).refCount())
+ dump(block->phis[i]);
+ }
dataLog(" vars before: ");
if (block->cfaHasVisited)
dumpOperands(block->valuesAtHead, WTF::dataFile());
@@ -274,8 +280,8 @@ void Graph::dump()
dataLog(" var links: ");
dumpOperands(block->variablesAtHead, WTF::dataFile());
dataLog("\n");
- for (size_t i = block->begin; i < block->end; ++i)
- dump(i);
+ for (size_t i = 0; i < block->size(); ++i)
+ dump(block->at(i));
dataLog(" vars after: ");
if (block->cfaHasVisited)
dumpOperands(block->valuesAtTail, WTF::dataFile());
@@ -283,15 +289,12 @@ void Graph::dump()
dataLog("<empty>");
dataLog("\n");
}
- dataLog("Phi Nodes:\n");
- for (size_t i = m_blocks.last()->end; i < size(); ++i)
- dump(i);
}
// FIXME: Convert this to be iterative, not recursive.
#define DO_TO_CHILDREN(node, thingToDo) do { \
Node& _node = (node); \
- if (_node.op & NodeHasVarArgs) { \
+ if (_node.flags & NodeHasVarArgs) { \
for (unsigned _childIdx = _node.firstChild(); \
_childIdx < _node.firstChild() + _node.numChildren(); \
_childIdx++) \
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 88d6a4eec..bacbac827 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -177,6 +177,12 @@ public:
return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger();
}
+ bool negateShouldSpeculateInteger(Node& negate)
+ {
+ ASSERT(negate.op == ArithNegate);
+ return at(negate.child1()).shouldSpeculateInteger() && negate.canSpeculateInteger();
+ }
+
bool addShouldSpeculateInteger(NodeIndex nodeIndex)
{
return addShouldSpeculateInteger(at(nodeIndex));
@@ -305,6 +311,41 @@ public:
return MethodOfGettingAValueProfile(valueProfileFor(nodeIndex));
}
+ bool needsActivation() const
+ {
+#if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
+ return true;
+#else
+ return m_codeBlock->needsFullScopeChain() && m_codeBlock->codeType() != GlobalCode;
+#endif
+ }
+
+ // Pass an argument index. Currently it's ignored, but that's somewhat
+ // of a bug.
+ bool argumentIsCaptured(int) const
+ {
+ return needsActivation();
+ }
+ bool localIsCaptured(int operand) const
+ {
+#if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
+ return operand < m_codeBlock->m_numVars;
+#else
+ return operand < m_codeBlock->m_numCapturedVars;
+#endif
+ }
+
+ bool isCaptured(int operand) const
+ {
+ if (operandIsArgument(operand))
+ return argumentIsCaptured(operandToArgument(operand));
+ return localIsCaptured(operand);
+ }
+ bool isCaptured(VirtualRegister virtualRegister) const
+ {
+ return isCaptured(static_cast<int>(virtualRegister));
+ }
+
JSGlobalData& m_globalData;
CodeBlock* m_codeBlock;
CodeBlock* m_profiledBlock;
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 7b2bbc788..af98f8d7a 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -44,7 +44,7 @@ void JITCompiler::linkOSRExits()
for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) {
OSRExit& exit = codeBlock()->osrExit(i);
exit.m_check.initialJump().link(this);
- store32(Imm32(i), &globalData()->osrExitIndex);
+ store32(TrustedImm32(i), &globalData()->osrExitIndex);
beginUninterruptedSequence();
exit.m_check.switchToLateJump(jump());
endUninterruptedSequence();
@@ -75,7 +75,7 @@ void JITCompiler::compileBody(SpeculativeJIT& speculative)
breakpoint();
#endif
- addPtr(Imm32(1), AbsoluteAddress(codeBlock()->addressOfSpeculativeSuccessCounter()));
+ addPtr(TrustedImm32(1), AbsoluteAddress(codeBlock()->addressOfSpeculativeSuccessCounter()));
bool compiledSpeculative = speculative.compile();
ASSERT_UNUSED(compiledSpeculative, compiledSpeculative);
@@ -195,7 +195,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
codeBlock()->shrinkWeakReferenceTransitionsToFit();
}
-void JITCompiler::compile(JITCode& entry)
+bool JITCompiler::compile(JITCode& entry)
{
compileEntry();
SpeculativeJIT speculative(*this);
@@ -204,14 +204,17 @@ void JITCompiler::compile(JITCode& entry)
// Create OSR entry trampolines if necessary.
speculative.createOSREntries();
- LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock);
+ LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock, JITCompilationCanFail);
+ if (linkBuffer.didFailToAllocate())
+ return false;
link(linkBuffer);
speculative.linkOSREntries(linkBuffer);
entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT);
+ return true;
}
-void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
+bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
{
compileEntry();
@@ -222,7 +225,7 @@ void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi
Label fromArityCheck(this);
// Plant a check that sufficient space is available in the RegisterFile.
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
- addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
+ addPtr(TrustedImm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
// Return here after register file check.
Label fromRegisterFileCheck = label();
@@ -258,7 +261,7 @@ void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi
compileEntry();
load32(AssemblyHelpers::payloadFor((VirtualRegister)RegisterFile::ArgumentCount), GPRInfo::regT1);
- branch32(AboveOrEqual, GPRInfo::regT1, Imm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this);
+ branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this);
move(stackPointerRegister, GPRInfo::argumentGPR0);
poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
token = beginCall();
@@ -272,7 +275,9 @@ void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi
// === Link ===
- LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock);
+ LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock, JITCompilationCanFail);
+ if (linkBuffer.didFailToAllocate())
+ return false;
link(linkBuffer);
speculative.linkOSREntries(linkBuffer);
@@ -282,6 +287,7 @@ void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi
entryWithArityCheck = linkBuffer.locationOf(arityCheck);
entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT);
+ return true;
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index a0c68fe4b..2df2703b0 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -194,8 +194,8 @@ public:
{
}
- void compile(JITCode& entry);
- void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
+ bool compile(JITCode& entry);
+ bool compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
// Accessors for properties.
Graph& graph() { return m_graph; }
@@ -297,12 +297,13 @@ public:
// value of (None, []). But the old JIT may stash some values there. So we really
// need (Top, TOP).
for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) {
- if (basicBlock.variablesAtHead.argument(argument) == NoNode)
+ NodeIndex nodeIndex = basicBlock.variablesAtHead.argument(argument);
+ if (nodeIndex == NoNode || !m_graph[nodeIndex].shouldGenerate())
entry->m_expectedValues.argument(argument).makeTop();
}
for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) {
NodeIndex nodeIndex = basicBlock.variablesAtHead.local(local);
- if (nodeIndex == NoNode)
+ if (nodeIndex == NoNode || !m_graph[nodeIndex].shouldGenerate())
entry->m_expectedValues.local(local).makeTop();
else if (m_graph[nodeIndex].variableAccessData()->shouldUseDoubleFormat())
entry->m_localsForcedDouble.set(local);
diff --git a/Source/JavaScriptCore/dfg/DFGNode.cpp b/Source/JavaScriptCore/dfg/DFGNode.cpp
new file mode 100644
index 000000000..c53817ba9
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGNode.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGNode.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+const char* arithNodeFlagsAsString(NodeFlags flags)
+{
+ flags &= NodeArithMask;
+
+ if (!flags)
+ return "<empty>";
+
+ static const int size = 64;
+ static char description[size];
+ BoundsCheckedPointer<char> ptr(description, size);
+
+ bool hasPrinted = false;
+
+ if (flags & NodeUsedAsNumber) {
+ ptr.strcat("UsedAsNum");
+ hasPrinted = true;
+ }
+
+ if (flags & NodeNeedsNegZero) {
+ if (hasPrinted)
+ ptr.strcat("|");
+ ptr.strcat("NeedsNegZero");
+ hasPrinted = true;
+ }
+
+ if (flags & NodeMayOverflow) {
+ if (hasPrinted)
+ ptr.strcat("|");
+ ptr.strcat("MayOverflow");
+ hasPrinted = true;
+ }
+
+ if (flags & NodeMayNegZero) {
+ if (hasPrinted)
+ ptr.strcat("|");
+ ptr.strcat("MayNegZero");
+ hasPrinted = true;
+ }
+
+ *ptr++ = 0;
+
+ return description;
+}
+
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 87dae7786..b672b67c5 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -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
@@ -57,36 +57,50 @@ struct StructureTransitionData {
}
};
-typedef unsigned ArithNodeFlags;
-#define NodeUseBottom 0x00
-#define NodeUsedAsNumber 0x01
-#define NodeNeedsNegZero 0x02
-#define NodeUsedAsMask 0x03
-#define NodeMayOverflow 0x04
-#define NodeMayNegZero 0x08
-#define NodeBehaviorMask 0x0c
+// Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
+// and some additional informative flags (must generate, is constant, etc).
+#define NodeResultMask 0xF
+#define NodeResultJS 0x1
+#define NodeResultNumber 0x2
+#define NodeResultInt32 0x3
+#define NodeResultBoolean 0x4
+#define NodeResultStorage 0x5
+#define NodeMustGenerate 0x10 // set on nodes that have side effects, and may not trivially be removed by DCE.
+#define NodeHasVarArgs 0x20
+#define NodeClobbersWorld 0x40
+#define NodeMightClobber 0x80
+#define NodeArithMask 0xF00
+#define NodeUseBottom 0x000
+#define NodeUsedAsNumber 0x100
+#define NodeNeedsNegZero 0x200
+#define NodeUsedAsMask 0x300
+#define NodeMayOverflow 0x400
+#define NodeMayNegZero 0x800
+#define NodeBehaviorMask 0xc00
-static inline bool nodeUsedAsNumber(ArithNodeFlags flags)
+typedef uint16_t NodeFlags;
+
+static inline bool nodeUsedAsNumber(NodeFlags flags)
{
return !!(flags & NodeUsedAsNumber);
}
-static inline bool nodeCanTruncateInteger(ArithNodeFlags flags)
+static inline bool nodeCanTruncateInteger(NodeFlags flags)
{
return !nodeUsedAsNumber(flags);
}
-static inline bool nodeCanIgnoreNegativeZero(ArithNodeFlags flags)
+static inline bool nodeCanIgnoreNegativeZero(NodeFlags flags)
{
return !(flags & NodeNeedsNegZero);
}
-static inline bool nodeMayOverflow(ArithNodeFlags flags)
+static inline bool nodeMayOverflow(NodeFlags flags)
{
return !!(flags & NodeMayOverflow);
}
-static inline bool nodeCanSpeculateInteger(ArithNodeFlags flags)
+static inline bool nodeCanSpeculateInteger(NodeFlags flags)
{
if (flags & NodeMayOverflow)
return !nodeUsedAsNumber(flags);
@@ -97,67 +111,7 @@ static inline bool nodeCanSpeculateInteger(ArithNodeFlags flags)
return true;
}
-static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
-{
- if (!flags)
- return "<empty>";
-
- static const int size = 64;
- static char description[size];
- BoundsCheckedPointer<char> ptr(description, size);
-
- bool hasPrinted = false;
-
- if (flags & NodeUsedAsNumber) {
- ptr.strcat("UsedAsNum");
- hasPrinted = true;
- }
-
- if (flags & NodeNeedsNegZero) {
- if (hasPrinted)
- ptr.strcat("|");
- ptr.strcat("NeedsNegZero");
- hasPrinted = true;
- }
-
- if (flags & NodeMayOverflow) {
- if (hasPrinted)
- ptr.strcat("|");
- ptr.strcat("MayOverflow");
- hasPrinted = true;
- }
-
- if (flags & NodeMayNegZero) {
- if (hasPrinted)
- ptr.strcat("|");
- ptr.strcat("MayNegZero");
- hasPrinted = true;
- }
-
- *ptr++ = 0;
-
- return description;
-}
-
-// Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
-// and some additional informative flags (must generate, is constant, etc).
-#define NodeIdMask 0xFFF
-#define NodeResultMask 0xF000
-#define NodeMustGenerate 0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE.
-#define NodeIsConstant 0x20000
-#define NodeIsJump 0x40000
-#define NodeIsBranch 0x80000
-#define NodeIsTerminal 0x100000
-#define NodeHasVarArgs 0x200000
-#define NodeClobbersWorld 0x400000
-#define NodeMightClobber 0x800000
-
-// These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result.
-#define NodeResultJS 0x1000
-#define NodeResultNumber 0x2000
-#define NodeResultInt32 0x3000
-#define NodeResultBoolean 0x4000
-#define NodeResultStorage 0x5000
+const char* arithNodeFlagsAsString(NodeFlags);
// This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
#define FOR_EACH_DFG_OP(macro) \
@@ -204,6 +158,7 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
/* Nodes for arithmetic operations. */\
macro(ArithAdd, NodeResultNumber) \
macro(ArithSub, NodeResultNumber) \
+ macro(ArithNegate, NodeResultNumber) \
macro(ArithMul, NodeResultNumber) \
macro(ArithDiv, NodeResultNumber) \
macro(ArithMod, NodeResultNumber) \
@@ -291,12 +246,23 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(StrCat, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
\
+ /* Nodes used for activations. Activation support works by having it anchored at */\
+ /* epilgoues via TearOffActivation, and all CreateActivation nodes kept alive by */\
+ /* being threaded with each other. */\
+ macro(CreateActivation, NodeResultJS) \
+ macro(TearOffActivation, NodeMustGenerate) \
+ \
+ /* Nodes for creating functions. */\
+ macro(NewFunctionNoCheck, NodeResultJS) \
+ macro(NewFunction, NodeResultJS) \
+ macro(NewFunctionExpression, NodeResultJS) \
+ \
/* Block terminals. */\
- macro(Jump, NodeMustGenerate | NodeIsTerminal | NodeIsJump) \
- macro(Branch, NodeMustGenerate | NodeIsTerminal | NodeIsBranch) \
- macro(Return, NodeMustGenerate | NodeIsTerminal) \
- macro(Throw, NodeMustGenerate | NodeIsTerminal) \
- macro(ThrowReferenceError, NodeMustGenerate | NodeIsTerminal) \
+ macro(Jump, NodeMustGenerate) \
+ macro(Branch, NodeMustGenerate) \
+ macro(Return, NodeMustGenerate) \
+ macro(Throw, NodeMustGenerate) \
+ macro(ThrowReferenceError, NodeMustGenerate) \
\
/* This is a pseudo-terminal. It means that execution should fall out of DFG at */\
/* this point, but execution does continue in the basic block - just in a */\
@@ -305,20 +271,25 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
// This enum generates a monotonically increasing id for all Node types,
// and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
-enum NodeId {
-#define DFG_OP_ENUM(opcode, flags) opcode##_id,
+enum NodeType {
+#define DFG_OP_ENUM(opcode, flags) opcode,
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
- LastNodeId
+ LastNodeType
};
-// Entries in this enum describe all Node types.
-// The enum value contains a monotonically increasing id, a result type, and additional flags.
-enum NodeType {
-#define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags),
+// Specifies the default flags for each node.
+inline NodeFlags defaultFlags(NodeType op)
+{
+ switch (op) {
+#define DFG_OP_ENUM(opcode, flags) case opcode: return flags;
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
-};
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
// This type used in passing an immediate argument to Node constructor;
// distinguishes an immediate value (typically an index into a CodeBlock data structure -
@@ -341,34 +312,32 @@ struct Node {
// Construct a node with up to 3 children, no immediate value.
Node(NodeType op, CodeOrigin codeOrigin, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
- : op(op)
- , codeOrigin(codeOrigin)
+ : codeOrigin(codeOrigin)
, children(NodeReferenceBlob::Fixed, child1, child2, child3)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
, m_prediction(PredictNone)
{
- ASSERT(!(op & NodeHasVarArgs));
- ASSERT(!hasArithNodeFlags());
+ setOpAndDefaultFlags(op);
+ ASSERT(!(flags & NodeHasVarArgs));
}
// Construct a node with up to 3 children and an immediate value.
Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
- : op(op)
- , codeOrigin(codeOrigin)
+ : codeOrigin(codeOrigin)
, children(NodeReferenceBlob::Fixed, child1, child2, child3)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
, m_opInfo(imm.m_value)
, m_prediction(PredictNone)
{
- ASSERT(!(op & NodeHasVarArgs));
+ setOpAndDefaultFlags(op);
+ ASSERT(!(flags & NodeHasVarArgs));
}
// Construct a node with up to 3 children and two immediate values.
Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
- : op(op)
- , codeOrigin(codeOrigin)
+ : codeOrigin(codeOrigin)
, children(NodeReferenceBlob::Fixed, child1, child2, child3)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
@@ -376,13 +345,13 @@ struct Node {
, m_opInfo2(safeCast<unsigned>(imm2.m_value))
, m_prediction(PredictNone)
{
- ASSERT(!(op & NodeHasVarArgs));
+ setOpAndDefaultFlags(op);
+ ASSERT(!(flags & NodeHasVarArgs));
}
// Construct a node with a variable number of children and two immediate values.
Node(VarArgTag, NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
- : op(op)
- , codeOrigin(codeOrigin)
+ : codeOrigin(codeOrigin)
, children(NodeReferenceBlob::Variable, firstChild, numChildren)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
@@ -390,12 +359,19 @@ struct Node {
, m_opInfo2(safeCast<unsigned>(imm2.m_value))
, m_prediction(PredictNone)
{
- ASSERT(op & NodeHasVarArgs);
+ setOpAndDefaultFlags(op);
+ ASSERT(flags & NodeHasVarArgs);
+ }
+
+ void setOpAndDefaultFlags(NodeType op)
+ {
+ this->op = op;
+ flags = defaultFlags(op);
}
bool mustGenerate()
{
- return op & NodeMustGenerate;
+ return flags & NodeMustGenerate;
}
bool isConstant()
@@ -520,6 +496,7 @@ struct Node {
case UInt32ToNumber:
case ArithAdd:
case ArithSub:
+ case ArithNegate:
case ArithMul:
case ArithAbs:
case ArithMin:
@@ -533,44 +510,32 @@ struct Node {
}
}
- ArithNodeFlags rawArithNodeFlags()
- {
- ASSERT(hasArithNodeFlags());
- return m_opInfo;
- }
-
// This corrects the arithmetic node flags, so that irrelevant bits are
// ignored. In particular, anything other than ArithMul does not need
// to know if it can speculate on negative zero.
- ArithNodeFlags arithNodeFlags()
+ NodeFlags arithNodeFlags()
{
- ArithNodeFlags result = rawArithNodeFlags();
+ NodeFlags result = flags & NodeArithMask;
if (op == ArithMul)
return result;
return result & ~NodeNeedsNegZero;
}
- ArithNodeFlags arithNodeFlagsForCompare()
- {
- if (hasArithNodeFlags())
- return arithNodeFlags();
- return 0;
- }
-
- void setArithNodeFlag(ArithNodeFlags flags)
+ void setArithNodeFlag(NodeFlags newFlags)
{
- ASSERT(hasArithNodeFlags());
- m_opInfo = flags;
+ ASSERT(!(newFlags & ~NodeArithMask));
+
+ flags &= ~NodeArithMask;
+ flags |= newFlags;
}
- bool mergeArithNodeFlags(ArithNodeFlags flags)
+ bool mergeArithNodeFlags(NodeFlags newFlags)
{
- if (!hasArithNodeFlags())
+ ASSERT(!(newFlags & ~NodeArithMask));
+ newFlags = flags | newFlags;
+ if (newFlags == flags)
return false;
- ArithNodeFlags newFlags = m_opInfo | flags;
- if (newFlags == m_opInfo)
- return false;
- m_opInfo = newFlags;
+ flags = newFlags;
return true;
}
@@ -626,42 +591,51 @@ struct Node {
bool hasResult()
{
- return op & NodeResultMask;
+ return flags & NodeResultMask;
}
bool hasInt32Result()
{
- return (op & NodeResultMask) == NodeResultInt32;
+ return (flags & NodeResultMask) == NodeResultInt32;
}
bool hasNumberResult()
{
- return (op & NodeResultMask) == NodeResultNumber;
+ return (flags & NodeResultMask) == NodeResultNumber;
}
bool hasJSResult()
{
- return (op & NodeResultMask) == NodeResultJS;
+ return (flags & NodeResultMask) == NodeResultJS;
}
bool hasBooleanResult()
{
- return (op & NodeResultMask) == NodeResultBoolean;
+ return (flags & NodeResultMask) == NodeResultBoolean;
}
bool isJump()
{
- return op & NodeIsJump;
+ return op == Jump;
}
bool isBranch()
{
- return op & NodeIsBranch;
+ return op == Branch;
}
bool isTerminal()
{
- return op & NodeIsTerminal;
+ switch (op) {
+ case Jump:
+ case Branch:
+ case Return:
+ case Throw:
+ case ThrowReferenceError:
+ return true;
+ default:
+ return false;
+ }
}
unsigned takenBytecodeOffsetDuringParsing()
@@ -775,6 +749,30 @@ struct Node {
unsigned storageAccessDataIndex()
{
+ ASSERT(hasStorageAccessData());
+ return m_opInfo;
+ }
+
+ bool hasFunctionDeclIndex()
+ {
+ return op == NewFunction
+ || op == NewFunctionNoCheck;
+ }
+
+ unsigned functionDeclIndex()
+ {
+ ASSERT(hasFunctionDeclIndex());
+ return m_opInfo;
+ }
+
+ bool hasFunctionExprIndex()
+ {
+ return op == NewFunctionExpression;
+ }
+
+ unsigned functionExprIndex()
+ {
+ ASSERT(hasFunctionExprIndex());
return m_opInfo;
}
@@ -799,7 +797,7 @@ struct Node {
bool shouldGenerate()
{
- return m_refCount && op != Phi && op != Flush;
+ return m_refCount;
}
unsigned refCount()
@@ -834,7 +832,7 @@ struct Node {
NodeUse child1()
{
- ASSERT(!(op & NodeHasVarArgs));
+ ASSERT(!(flags & NodeHasVarArgs));
return children.child1();
}
@@ -848,25 +846,25 @@ struct Node {
NodeUse child2()
{
- ASSERT(!(op & NodeHasVarArgs));
+ ASSERT(!(flags & NodeHasVarArgs));
return children.child2();
}
NodeUse child3()
{
- ASSERT(!(op & NodeHasVarArgs));
+ ASSERT(!(flags & NodeHasVarArgs));
return children.child3();
}
unsigned firstChild()
{
- ASSERT(op & NodeHasVarArgs);
+ ASSERT(flags & NodeHasVarArgs);
return children.firstChild();
}
unsigned numChildren()
{
- ASSERT(op & NodeHasVarArgs);
+ ASSERT(flags & NodeHasVarArgs);
return children.numChildren();
}
@@ -1032,8 +1030,8 @@ struct Node {
fprintf(out, ", @%u", child3().index());
}
- // This enum value describes the type of the node.
- NodeType op;
+ uint16_t op; // real type is NodeType
+ NodeFlags flags;
// Used to look up exception handling information (currently implemented as a bytecode index).
CodeOrigin codeOrigin;
// References to up to 3 children, or links to a variable length set of children.
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
index a672234a3..bd45020d1 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp
@@ -98,7 +98,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
m_jit.store32(scratch, &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload);
m_jit.load32(scratchBuffer, scratch);
} else if (exit.m_jsValueSource.hasKnownTag()) {
- m_jit.store32(AssemblyHelpers::Imm32(exit.m_jsValueSource.tag()), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag);
+ m_jit.store32(AssemblyHelpers::TrustedImm32(exit.m_jsValueSource.tag()), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag);
m_jit.store32(exit.m_jsValueSource.payloadGPR(), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload);
} else {
m_jit.store32(exit.m_jsValueSource.tagGPR(), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag);
@@ -562,32 +562,40 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// counter to 0; otherwise we set the counter to
// counterValueForOptimizeAfterWarmUp().
- m_jit.add32(AssemblyHelpers::Imm32(1), AssemblyHelpers::AbsoluteAddress(&exit.m_count));
+ m_jit.add32(AssemblyHelpers::TrustedImm32(1), AssemblyHelpers::AbsoluteAddress(&exit.m_count));
m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.codeBlock()), GPRInfo::regT0);
m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()), GPRInfo::regT2);
m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()), GPRInfo::regT1);
- m_jit.add32(AssemblyHelpers::Imm32(1), GPRInfo::regT2);
- m_jit.add32(AssemblyHelpers::Imm32(-1), GPRInfo::regT1);
+ m_jit.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
+ m_jit.add32(AssemblyHelpers::TrustedImm32(-1), GPRInfo::regT1);
m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()));
m_jit.store32(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()));
m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0);
- AssemblyHelpers::Jump fewFails = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::Imm32(m_jit.codeBlock()->largeFailCountThreshold()));
- m_jit.mul32(AssemblyHelpers::Imm32(Options::desiredSpeculativeSuccessFailRatio), GPRInfo::regT2, GPRInfo::regT2);
+ AssemblyHelpers::Jump fewFails = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(m_jit.codeBlock()->largeFailCountThreshold()));
+ m_jit.mul32(AssemblyHelpers::TrustedImm32(Options::desiredSpeculativeSuccessFailRatio), GPRInfo::regT2, GPRInfo::regT2);
AssemblyHelpers::Jump lowFailRate = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1);
// Reoptimize as soon as possible.
- m_jit.store32(AssemblyHelpers::Imm32(Options::executionCounterValueForOptimizeNextInvocation), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(0), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(0), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold()));
AssemblyHelpers::Jump doneAdjusting = m_jit.jump();
fewFails.link(&m_jit);
lowFailRate.link(&m_jit);
- m_jit.store32(AssemblyHelpers::Imm32(m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp()), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ // Adjust the execution counter such that the target is to only optimize after a while.
+ int32_t targetValue =
+ ExecutionCounter::applyMemoryUsageHeuristicsAndConvertToInt(
+ m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp(),
+ m_jit.baselineCodeBlock());
+ m_jit.store32(AssemblyHelpers::TrustedImm32(-targetValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(targetValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(ExecutionCounter::formattedTotalCount(targetValue)), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionTotalCount()));
doneAdjusting.link(&m_jit);
@@ -618,24 +626,24 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
GPRReg callerFrameGPR;
if (inlineCallFrame->caller.inlineCallFrame) {
- m_jit.add32(AssemblyHelpers::Imm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
+ m_jit.add32(AssemblyHelpers::TrustedImm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
callerFrameGPR = GPRInfo::regT3;
} else
callerFrameGPR = GPRInfo::callFrameRegister;
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CodeBlock)));
- m_jit.store32(AssemblyHelpers::Imm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ScopeChain)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ScopeChain)));
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee->scope()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ScopeChain)));
- m_jit.store32(AssemblyHelpers::Imm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CallerFrame)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CallerFrame)));
m_jit.storePtr(callerFrameGPR, AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CallerFrame)));
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ReturnPC)));
- m_jit.store32(AssemblyHelpers::Imm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
- m_jit.store32(AssemblyHelpers::Imm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
}
if (exit.m_codeOrigin.inlineCallFrame)
- m_jit.addPtr(AssemblyHelpers::Imm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
+ m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
// 14) Jump into the corresponding baseline JIT code.
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
index f5e03973c..91a515c48 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
@@ -227,7 +227,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
break;
case AlreadyInRegisterFileAsUnboxedInt32:
- m_jit.store32(AssemblyHelpers::Imm32(static_cast<uint32_t>(TagTypeNumber >> 32)), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(static_cast<uint32_t>(TagTypeNumber >> 32)), AssemblyHelpers::tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
break;
case UInt32InGPR: {
@@ -541,32 +541,40 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
// counter to 0; otherwise we set the counter to
// counterValueForOptimizeAfterWarmUp().
- m_jit.add32(AssemblyHelpers::Imm32(1), AssemblyHelpers::AbsoluteAddress(&exit.m_count));
+ m_jit.add32(AssemblyHelpers::TrustedImm32(1), AssemblyHelpers::AbsoluteAddress(&exit.m_count));
m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.codeBlock()), GPRInfo::regT0);
m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()), GPRInfo::regT2);
m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()), GPRInfo::regT1);
- m_jit.add32(AssemblyHelpers::Imm32(1), GPRInfo::regT2);
- m_jit.add32(AssemblyHelpers::Imm32(-1), GPRInfo::regT1);
+ m_jit.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
+ m_jit.add32(AssemblyHelpers::TrustedImm32(-1), GPRInfo::regT1);
m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()));
m_jit.store32(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()));
m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0);
- AssemblyHelpers::Jump fewFails = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::Imm32(m_jit.codeBlock()->largeFailCountThreshold()));
- m_jit.mul32(AssemblyHelpers::Imm32(Options::desiredSpeculativeSuccessFailRatio), GPRInfo::regT2, GPRInfo::regT2);
+ AssemblyHelpers::Jump fewFails = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(m_jit.codeBlock()->largeFailCountThreshold()));
+ m_jit.mul32(AssemblyHelpers::TrustedImm32(Options::desiredSpeculativeSuccessFailRatio), GPRInfo::regT2, GPRInfo::regT2);
AssemblyHelpers::Jump lowFailRate = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1);
// Reoptimize as soon as possible.
- m_jit.store32(AssemblyHelpers::Imm32(Options::executionCounterValueForOptimizeNextInvocation), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(0), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(0), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold()));
AssemblyHelpers::Jump doneAdjusting = m_jit.jump();
fewFails.link(&m_jit);
lowFailRate.link(&m_jit);
- m_jit.store32(AssemblyHelpers::Imm32(m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp()), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ // Adjust the execution counter such that the target is to only optimize after a while.
+ int32_t targetValue =
+ ExecutionCounter::applyMemoryUsageHeuristicsAndConvertToInt(
+ m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp(),
+ m_jit.baselineCodeBlock());
+ m_jit.store32(AssemblyHelpers::TrustedImm32(-targetValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(targetValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold()));
+ m_jit.store32(AssemblyHelpers::TrustedImm32(ExecutionCounter::formattedTotalCount(targetValue)), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionTotalCount()));
doneAdjusting.link(&m_jit);
@@ -595,7 +603,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
GPRReg callerFrameGPR;
if (inlineCallFrame->caller.inlineCallFrame) {
- m_jit.addPtr(AssemblyHelpers::Imm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
+ m_jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
callerFrameGPR = GPRInfo::regT3;
} else
callerFrameGPR = GPRInfo::callFrameRegister;
@@ -609,7 +617,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco
}
if (exit.m_codeOrigin.inlineCallFrame)
- m_jit.addPtr(AssemblyHelpers::Imm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
+ m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
// 16) Jump into the corresponding baseline JIT code.
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 165a21416..304c54d95 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -31,10 +31,12 @@
#include "DFGRepatch.h"
#include "HostCallReturnValue.h"
#include "GetterSetter.h"
-#include "InlineASM.h"
+#include <wtf/InlineASM.h>
#include "Interpreter.h"
+#include "JSActivation.h"
#include "JSByteArray.h"
#include "JSGlobalData.h"
+#include "JSStaticScopeObject.h"
#include "Operations.h"
#if ENABLE(DFG_JIT)
@@ -144,6 +146,7 @@ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function)
namespace JSC { namespace DFG {
+template<bool strict>
static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
{
JSGlobalData* globalData = &exec->globalData();
@@ -155,7 +158,7 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index,
return;
}
- JSArray::putByIndex(array, exec, index, value);
+ JSArray::putByIndex(array, exec, index, value, strict);
return;
}
@@ -173,7 +176,7 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index,
}
}
- baseValue.put(exec, index, value);
+ baseValue.putByIndex(exec, index, value, strict);
}
template<bool strict>
@@ -187,7 +190,7 @@ ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exe
JSValue value = JSValue::decode(encodedValue);
if (LIKELY(property.isUInt32())) {
- putByVal(exec, baseValue, property.asUInt32(), value);
+ putByVal<strict>(exec, baseValue, property.asUInt32(), value);
return;
}
@@ -195,7 +198,7 @@ ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exe
double propertyAsDouble = property.asDouble();
uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
if (propertyAsDouble == propertyAsUInt32) {
- putByVal(exec, baseValue, propertyAsUInt32, value);
+ putByVal<strict>(exec, baseValue, propertyAsUInt32, value);
return;
}
}
@@ -471,14 +474,24 @@ void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell,
operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}
-void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
+void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
+{
+ JSGlobalData* globalData = &exec->globalData();
+ NativeCallFrameTracer tracer(globalData, exec);
+
+ // We should only get here if index is outside the existing vector.
+ ASSERT(!array->canSetIndex(index));
+ JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue), true);
+}
+
+void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
// We should only get here if index is outside the existing vector.
ASSERT(!array->canSetIndex(index));
- JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue));
+ JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue), false);
}
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
@@ -734,8 +747,11 @@ size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue en
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
+
+ JSValue src1 = JSValue::decode(encodedOp1);
+ JSValue src2 = JSValue::decode(encodedOp2);
- return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
+ return JSValue::strictEqual(exec, src1, src2);
}
static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
@@ -974,6 +990,43 @@ EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr
return JSValue::encode(RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp));
}
+JSCell* DFG_OPERATION operationCreateActivation(ExecState* exec)
+{
+ JSGlobalData& globalData = exec->globalData();
+ JSActivation* activation = JSActivation::create(
+ globalData, exec, static_cast<FunctionExecutable*>(exec->codeBlock()->ownerExecutable()));
+ exec->setScopeChain(exec->scopeChain()->push(activation));
+ return activation;
+}
+
+void DFG_OPERATION operationTearOffActivation(ExecState* exec, JSCell* activation)
+{
+ ASSERT(activation);
+ ASSERT(activation->inherits(&JSActivation::s_info));
+ static_cast<JSActivation*>(activation)->tearOff(exec->globalData());
+}
+
+JSCell* DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable)
+{
+ ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info));
+ return static_cast<FunctionExecutable*>(functionExecutable)->make(exec, exec->scopeChain());
+}
+
+JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell)
+{
+ ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info));
+ FunctionExecutable* functionExecutable =
+ static_cast<FunctionExecutable*>(functionExecutableAsCell);
+ JSFunction *function = functionExecutable->make(exec, exec->scopeChain());
+ if (!functionExecutable->name().isNull()) {
+ JSStaticScopeObject* functionScopeObject =
+ JSStaticScopeObject::create(
+ exec, functionExecutable->name(), function, ReadOnly | DontDelete);
+ function->setScope(exec->globalData(), function->scope()->push(functionScopeObject));
+ }
+ return function;
+}
+
DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t callIndex)
{
JSGlobalData* globalData = &exec->globalData();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index cdb88de27..4ca58d621 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -89,6 +89,7 @@ typedef void DFG_OPERATION (*V_DFGOperation_EAZJ)(ExecState*, JSArray*, int32_t,
typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
typedef double DFG_OPERATION (*D_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*);
+typedef void DFG_OPERATION (V_DFGOperation_EC)(ExecState*, JSCell*);
// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
JSCell* DFG_OPERATION operationNewObject(ExecState*);
@@ -118,7 +119,8 @@ void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBas
void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
-void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
+void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
+void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*);
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*);
void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
@@ -145,6 +147,10 @@ void* DFG_OPERATION operationVirtualCall(ExecState*);
void* DFG_OPERATION operationLinkCall(ExecState*);
void* DFG_OPERATION operationVirtualConstruct(ExecState*);
void* DFG_OPERATION operationLinkConstruct(ExecState*);
+JSCell* DFG_OPERATION operationCreateActivation(ExecState*);
+void DFG_OPERATION operationTearOffActivation(ExecState*, JSCell*);
+JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*);
+JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*);
// This method is used to lookup an exception hander, keyed by faultLocation, which is
// the return location from one of the calls out to one of the helper operations above.
diff --git a/Source/JavaScriptCore/dfg/DFGPhase.cpp b/Source/JavaScriptCore/dfg/DFGPhase.cpp
index bc1eabff4..bae12b1cc 100644
--- a/Source/JavaScriptCore/dfg/DFGPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPhase.cpp
@@ -35,7 +35,7 @@ void Phase::beginPhase()
{
dataLog("Beginning DFG phase %s.\n", m_name);
dataLog("Graph before %s:\n", m_name);
- m_graph.dump(m_codeBlock);
+ m_graph.dump();
}
void Phase::endPhase()
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index b4c9e075a..98bdaac06 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -105,7 +105,7 @@ private:
if (!node.shouldGenerate())
return;
- NodeType op = node.op;
+ NodeType op = static_cast<NodeType>(node.op);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" %s @%u: ", Graph::opName(op), m_compileIndex);
@@ -209,6 +209,15 @@ private:
break;
}
+ case ArithNegate:
+ if (m_graph[node.child1()].prediction()) {
+ if (m_graph.negateShouldSpeculateInteger(node))
+ changed |= mergePrediction(PredictInt32);
+ else
+ changed |= mergePrediction(PredictDouble);
+ }
+ break;
+
case ArithMul:
case ArithMin:
case ArithMax:
@@ -397,6 +406,18 @@ private:
break;
}
+ case CreateActivation: {
+ changed |= setPrediction(PredictObjectOther);
+ break;
+ }
+
+ case NewFunction:
+ case NewFunctionNoCheck:
+ case NewFunctionExpression: {
+ changed |= setPrediction(PredictFunction);
+ break;
+ }
+
case GetArrayLength:
case GetByteArrayLength:
case GetInt8ArrayLength:
@@ -415,6 +436,9 @@ private:
break;
}
+ case Flush:
+ break;
+
#ifndef NDEBUG
// These get ignored because they don't return anything.
case PutScopedVar:
@@ -424,7 +448,6 @@ private:
case Return:
case CheckHasInstance:
case Phi:
- case Flush:
case Throw:
case ThrowReferenceError:
case ForceOSRExit:
@@ -437,6 +460,7 @@ private:
case CheckFunction:
case PutStructure:
case PutByOffset:
+ case TearOffActivation:
break;
// These gets ignored because it doesn't do anything.
@@ -444,6 +468,10 @@ private:
case InlineStart:
case Nop:
break;
+
+ case LastNodeType:
+ ASSERT_NOT_REACHED();
+ break;
#else
default:
break;
@@ -492,7 +520,7 @@ private:
void vote(Node& node, VariableAccessData::Ballot ballot)
{
- if (node.op & NodeHasVarArgs) {
+ if (node.flags & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
vote(m_graph.m_varArgChildren[childIdx], ballot);
return;
@@ -586,8 +614,13 @@ private:
break;
}
}
- for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
- m_changed |= m_graph.m_variableAccessData[i].find()->tallyVotesForShouldUseDoubleFormat();
+ for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
+ VariableAccessData* variableAccessData = m_graph.m_variableAccessData[i].find();
+ if (operandIsArgument(variableAccessData->local())
+ || m_graph.isCaptured(variableAccessData->local()))
+ continue;
+ m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
+ }
}
void fixupNode(Node& node)
@@ -595,7 +628,7 @@ private:
if (!node.shouldGenerate())
return;
- NodeType op = node.op;
+ NodeType op = static_cast<NodeType>(node.op);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" %s @%u: ", Graph::opName(op), m_compileIndex);
@@ -651,13 +684,16 @@ private:
node.op = GetFloat64ArrayLength;
else
ASSERT_NOT_REACHED();
- m_graph.deref(m_compileIndex); // No longer MustGenerate
+ // No longer MustGenerate
+ ASSERT(node.flags & NodeMustGenerate);
+ node.flags &= ~NodeMustGenerate;
+ m_graph.deref(m_compileIndex);
break;
}
case GetIndexedPropertyStorage: {
PredictedType basePrediction = m_graph[node.child2()].prediction();
if (!(basePrediction & PredictInt32) && basePrediction) {
- node.op = Nop;
+ node.setOpAndDefaultFlags(Nop);
m_graph.clearAndDerefChild1(node);
m_graph.clearAndDerefChild2(node);
m_graph.clearAndDerefChild3(node);
diff --git a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
new file mode 100644
index 000000000..fb30de742
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGRedundantPhiEliminationPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+
+namespace JSC { namespace DFG {
+
+class RedundantPhiEliminationPhase : public Phase {
+public:
+ RedundantPhiEliminationPhase(Graph& graph)
+ : Phase(graph, "redundant phi elimination")
+ {
+ }
+
+ void run()
+ {
+ bool changed = false;
+ do {
+ changed = fixupPhis();
+ } while (changed);
+
+ updateBlockVariableInformation();
+
+ // Update the Phi references from non-Phi nodes, e.g., the GetLocals.
+ for (NodeIndex index = 0; index < m_graph.size(); ++index) {
+ Node& node = m_graph[index];
+
+ if (!node.shouldGenerate())
+ continue;
+
+ switch (node.op) {
+ case GetLocal:
+ replacePhiChild(node, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+private:
+ NodeIndex getRedundantReplacement(NodeIndex phi)
+ {
+ NodeIndex child1 = m_graph[phi].child1().indexUnchecked();
+ NodeIndex candidate = child1 == phi ? NoNode : child1;
+
+ NodeIndex child2 = m_graph[phi].child2().indexUnchecked();
+ if (candidate != NoNode) {
+ if (child2 != NoNode && child2 != candidate && child2 != phi)
+ return NoNode;
+ } else if (child2 != phi)
+ candidate = child2;
+
+ NodeIndex child3 = m_graph[phi].child3().indexUnchecked();
+ if (candidate != NoNode) {
+ if (child3 != NoNode && child3 != candidate && child3 != phi)
+ return NoNode;
+ } else if (child3 != phi)
+ candidate = child3;
+
+ return candidate;
+ }
+
+ bool replacePhiChild(Node& node, unsigned childIndex)
+ {
+ ASSERT(childIndex < 3);
+
+ bool replaced = false;
+ NodeIndex child = node.children.child(childIndex).indexUnchecked();
+ if (child != NoNode && m_graph[child].op == Phi) {
+ NodeIndex childReplacement = getRedundantReplacement(child);
+ if (childReplacement != NoNode) {
+ node.children.child(childIndex).setIndex(childReplacement);
+ replaced = true;
+ if (node.refCount()) {
+ m_graph[childReplacement].ref();
+ m_graph.deref(child);
+ }
+ }
+ }
+ return replaced;
+ }
+
+ bool fixupPhis()
+ {
+ bool changed = false;
+
+ for (BlockIndex block = 0; block < m_graph.m_blocks.size(); ++block) {
+ Vector<NodeIndex>& phis = m_graph.m_blocks[block]->phis;
+
+ for (size_t i = 0; i < phis.size(); ++i) {
+ NodeIndex phi = phis[i];
+ Node& phiNode = m_graph[phi];
+
+ changed |= (replacePhiChild(phiNode, 0) && phiNode.refCount());
+ changed |= (replacePhiChild(phiNode, 1) && phiNode.refCount());
+ changed |= (replacePhiChild(phiNode, 2) && phiNode.refCount());
+ }
+ }
+
+ return changed;
+ }
+
+ void updateBlockVariableInformation()
+ {
+ // Redundant Phi nodes are eliminated, we need to update
+ // the variable information if it references them.
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+ BasicBlock* basicBlock = m_graph.m_blocks[blockIndex].get();
+
+ for (size_t arg = 0; arg < basicBlock->variablesAtHead.numberOfArguments(); ++arg) {
+ NodeIndex nodeIndex = basicBlock->variablesAtHead.argument(arg);
+ if (nodeIndex != NoNode && m_graph[nodeIndex].op == Phi && !m_graph[nodeIndex].refCount()) {
+ NodeIndex replacement = getRedundantReplacement(nodeIndex);
+ if (replacement != NoNode) {
+ // This argument must be unused in this block.
+ ASSERT(basicBlock->variablesAtTail.argument(arg) == nodeIndex);
+ basicBlock->variablesAtHead.argument(arg) = replacement;
+ basicBlock->variablesAtTail.argument(arg) = replacement;
+ }
+ }
+ }
+
+ for (size_t local = 0; local < basicBlock->variablesAtHead.numberOfLocals(); ++local) {
+ NodeIndex nodeIndex = basicBlock->variablesAtHead.local(local);
+ if (nodeIndex != NoNode && m_graph[nodeIndex].op == Phi && !m_graph[nodeIndex].refCount()) {
+ NodeIndex replacement = getRedundantReplacement(nodeIndex);
+ if (replacement != NoNode) {
+ // This local variable must be unused in this block.
+ ASSERT(basicBlock->variablesAtTail.local(local) == nodeIndex);
+ basicBlock->variablesAtHead.local(local) = replacement;
+ basicBlock->variablesAtTail.local(local) = replacement;
+ }
+ }
+ }
+ }
+ }
+
+};
+
+void performRedundantPhiElimination(Graph& graph)
+{
+ runPhase<RedundantPhiEliminationPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h
new file mode 100644
index 000000000..202ab4441
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGRedundantPhiEliminationPhase_h
+#define DFGRedundantPhiEliminationPhase_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGPhase.h"
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// We inserted many can-be-redundant Phi nodes when building the graph.
+// This phase will just remove them.
+
+void performRedundantPhiElimination(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGRedundantPhiEliminationPhase_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGScoreBoard.h b/Source/JavaScriptCore/dfg/DFGScoreBoard.h
index 912b3e8fd..140de185b 100644
--- a/Source/JavaScriptCore/dfg/DFGScoreBoard.h
+++ b/Source/JavaScriptCore/dfg/DFGScoreBoard.h
@@ -58,14 +58,27 @@ public:
}
}
-#if DFG_ENABLE(CONSISTENCY_CHECK)
~ScoreBoard()
{
- // For every entry in the used list the use count of the virtual register should be zero.
- for (size_t i = 0; i < m_free.size(); ++i)
- ASSERT(!m_used[i] || m_used[i] == max());
+ assertClear();
}
+
+ void assertClear()
+ {
+#if !ASSERT_DISABLED
+ // For every entry in the used list the use count of the virtual register should be zero, or max, due to it being a preserved local.
+ for (size_t i = 0; i < m_used.size(); ++i)
+ ASSERT(!m_used[i] || m_used[i] == max());
+ // For every entry in the free list, the use count should be zero.
+ for (size_t i = 0; i < m_free.size(); ++i)
+ ASSERT(!m_used[m_free[i]]);
+ // There must not be duplicates in the free list.
+ for (size_t i = 0; i < m_free.size(); ++i) {
+ for (size_t j = i + 1; j < m_free.size(); ++j)
+ ASSERT(m_free[i] != m_free[j]);
+ }
#endif
+ }
VirtualRegister allocate()
{
@@ -99,6 +112,9 @@ public:
uint32_t index = node.virtualRegister();
ASSERT(m_used[index] != max());
if (node.refCount() == ++m_used[index]) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Freeing virtual register %u.", index);
+#endif
// If the use count in the scoreboard reaches the use count for the node,
// then this was its last use; the virtual register is now free.
// Clear the use count & add to the free list.
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 8578337f5..7bcb44576 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -83,7 +83,7 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
void SpeculativeJIT::useChildren(Node& node)
{
- if (node.op & NodeHasVarArgs) {
+ if (node.flags & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
use(m_jit.graph().m_varArgChildren[childIdx]);
} else {
@@ -365,12 +365,15 @@ void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueGPR, NodeUse valueU
bool SpeculativeJIT::nonSpeculativeCompare(Node& node, MacroAssembler::RelationalCondition cond, S_DFGOperation_EJJ helperFunction)
{
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+
ASSERT(node.adjustedRefCount() == 1);
nonSpeculativePeepholeBranch(node, branchNodeIndex, cond, helperFunction);
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
@@ -383,15 +386,15 @@ bool SpeculativeJIT::nonSpeculativeCompare(Node& node, MacroAssembler::Relationa
bool SpeculativeJIT::nonSpeculativeStrictEq(Node& node, bool invert)
{
- if (!invert && (isKnownNumeric(node.child1().index()) || isKnownNumeric(node.child2().index())))
- return nonSpeculativeCompare(node, MacroAssembler::Equal, operationCompareStrictEq);
-
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+
ASSERT(node.adjustedRefCount() == 1);
nonSpeculativePeepholeStrictEq(node, branchNodeIndex, invert);
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
@@ -765,7 +768,6 @@ FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1)
}
#endif
-#ifndef NDEBUG
void ValueSource::dump(FILE* out) const
{
switch (kind()) {
@@ -792,7 +794,6 @@ void ValueSource::dump(FILE* out) const
break;
}
}
-#endif
void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)
{
@@ -873,8 +874,10 @@ void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNo
bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
{
// Fused compare & branch.
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+
// detectPeepHoleBranch currently only permits the branch to be the very next node,
// so can be no intervening nodes to also reference the compare.
ASSERT(node.adjustedRefCount() == 1);
@@ -898,6 +901,7 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::Relationa
} else
nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
@@ -915,12 +919,9 @@ void SpeculativeJIT::compileMovHint(Node& node)
void SpeculativeJIT::compile(BasicBlock& block)
{
ASSERT(m_compileOkay);
- ASSERT(m_compileIndex == block.begin);
- if (!block.isReachable) {
- m_compileIndex = block.end;
+ if (!block.isReachable)
return;
- }
m_blockHeads[m_block] = m_jit.label();
#if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
@@ -930,7 +931,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
for (size_t i = 0; i < m_arguments.size(); ++i) {
NodeIndex nodeIndex = block.variablesAtHead.argument(i);
- if (nodeIndex == NoNode)
+ if (nodeIndex == NoNode || m_jit.graph().argumentIsCaptured(i))
m_arguments[i] = ValueSource(ValueInRegisterFile);
else
m_arguments[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
@@ -942,7 +943,7 @@ 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);
- if (nodeIndex == NoNode)
+ if (nodeIndex == NoNode || m_jit.graph().localIsCaptured(i))
m_variables[i] = ValueSource(ValueInRegisterFile);
else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat())
m_variables[i] = ValueSource(DoubleInRegisterFile);
@@ -955,12 +956,13 @@ void SpeculativeJIT::compile(BasicBlock& block)
if (DFG_ENABLE_EDGE_CODE_VERIFICATION) {
JITCompiler::Jump verificationSucceeded =
- m_jit.branch32(JITCompiler::Equal, GPRInfo::regT0, Imm32(m_block));
+ m_jit.branch32(JITCompiler::Equal, GPRInfo::regT0, TrustedImm32(m_block));
m_jit.breakpoint();
verificationSucceeded.link(&m_jit);
}
- for (; m_compileIndex < block.end; ++m_compileIndex) {
+ for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
+ m_compileIndex = block[m_indexInBlock];
Node& node = at(m_compileIndex);
m_codeOriginForOSR = node.codeOrigin;
if (!node.shouldGenerate()) {
@@ -1005,7 +1007,6 @@ void SpeculativeJIT::compile(BasicBlock& block)
compile(node);
if (!m_compileOkay) {
m_compileOkay = true;
- m_compileIndex = block.end;
clearGenerationInfo();
return;
}
@@ -1045,7 +1046,7 @@ void SpeculativeJIT::compile(BasicBlock& block)
#endif
// Make sure that the abstract state is rematerialized for the next node.
- m_state.execute(m_compileIndex);
+ m_state.execute(m_indexInBlock);
if (node.shouldGenerate())
checkConsistency();
@@ -1232,7 +1233,7 @@ bool SpeculativeJIT::compile()
checkArgumentTypes();
if (DFG_ENABLE_EDGE_CODE_VERIFICATION)
- m_jit.move(Imm32(0), GPRInfo::regT0);
+ m_jit.move(TrustedImm32(0), GPRInfo::regT0);
ASSERT(!m_compileIndex);
for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)
@@ -1258,7 +1259,7 @@ void SpeculativeJIT::createOSREntries()
}
m_osrEntryHeads.append(m_jit.label());
- m_jit.move(Imm32(blockIndex), GPRInfo::regT0);
+ m_jit.move(TrustedImm32(blockIndex), GPRInfo::regT0);
m_jit.jump().linkTo(m_blockHeads[blockIndex], &m_jit);
}
}
@@ -2318,8 +2319,14 @@ void SpeculativeJIT::compileArithSub(Node& node)
if (nodeCanTruncateInteger(node.arithNodeFlags())) {
m_jit.move(op1.gpr(), result.gpr());
m_jit.sub32(Imm32(imm2), result.gpr());
- } else
+ } else {
+#if ENABLE(JIT_CONSTANT_BLINDING)
+ GPRTemporary scratch(this);
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr(), scratch.gpr()));
+#else
speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+#endif
+ }
integerResult(result.gpr(), m_compileIndex);
return;
@@ -2365,6 +2372,34 @@ void SpeculativeJIT::compileArithSub(Node& node)
doubleResult(result.fpr(), m_compileIndex);
}
+void SpeculativeJIT::compileArithNegate(Node& node)
+{
+ if (m_jit.graph().negateShouldSpeculateInteger(node)) {
+ SpeculateIntegerOperand op1(this, node.child1());
+ GPRTemporary result(this);
+
+ m_jit.move(op1.gpr(), result.gpr());
+
+ if (nodeCanTruncateInteger(node.arithNodeFlags()))
+ m_jit.neg32(result.gpr());
+ else {
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchNeg32(MacroAssembler::Overflow, result.gpr()));
+ if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags()))
+ speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, result.gpr()));
+ }
+
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ SpeculateDoubleOperand op1(this, node.child1());
+ FPRTemporary result(this);
+
+ m_jit.negateDouble(op1.fpr(), result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+}
+
void SpeculativeJIT::compileArithMul(Node& node)
{
if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
@@ -2456,8 +2491,9 @@ bool SpeculativeJIT::compileStrictEqForConstant(Node& node, NodeUse value, JSVal
{
JSValueOperand op1(this, value);
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
Node& branchNode = at(branchNodeIndex);
BlockIndex taken = branchNode.takenBlockIndex();
BlockIndex notTaken = branchNode.notTakenBlockIndex();
@@ -2493,6 +2529,7 @@ bool SpeculativeJIT::compileStrictEqForConstant(Node& node, NodeUse value, JSVal
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
@@ -2504,18 +2541,18 @@ bool SpeculativeJIT::compileStrictEqForConstant(Node& node, NodeUse value, JSVal
GPRReg resultGPR = result.gpr();
m_jit.move(MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(ValueFalse)), resultGPR);
MacroAssembler::Jump notEqual = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(constant))));
- m_jit.or32(MacroAssembler::Imm32(1), resultGPR);
+ m_jit.or32(MacroAssembler::TrustedImm32(1), resultGPR);
notEqual.link(&m_jit);
jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
#else
GPRReg op1PayloadGPR = op1.payloadGPR();
GPRReg op1TagGPR = op1.tagGPR();
GPRReg resultGPR = result.gpr();
- m_jit.move(Imm32(0), resultGPR);
+ m_jit.move(TrustedImm32(0), resultGPR);
MacroAssembler::JumpList notEqual;
notEqual.append(m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, MacroAssembler::Imm32(constant.tag())));
notEqual.append(m_jit.branch32(MacroAssembler::NotEqual, op1PayloadGPR, MacroAssembler::Imm32(constant.payload())));
- m_jit.move(Imm32(1), resultGPR);
+ m_jit.move(TrustedImm32(1), resultGPR);
notEqual.link(&m_jit);
booleanResult(resultGPR, m_compileIndex);
#endif
@@ -2543,11 +2580,13 @@ bool SpeculativeJIT::compileStrictEq(Node& node)
// 2) If the operands are predicted integer, do an integer comparison.
if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
compilePeepHoleIntegerBranch(node, branchNodeIndex, MacroAssembler::Equal);
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
@@ -2558,11 +2597,13 @@ bool SpeculativeJIT::compileStrictEq(Node& node)
// 3) If the operands are predicted double, do a double comparison.
if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
compilePeepHoleDoubleBranch(node, branchNodeIndex, MacroAssembler::DoubleEqual);
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
@@ -2574,11 +2615,13 @@ bool SpeculativeJIT::compileStrictEq(Node& node)
// or array comparison.
if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectPrediction);
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
@@ -2587,11 +2630,13 @@ bool SpeculativeJIT::compileStrictEq(Node& node)
}
if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArrayPrediction);
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
}
@@ -2691,6 +2736,28 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
storageResult(storageReg, m_compileIndex);
}
+void SpeculativeJIT::compileNewFunctionNoCheck(Node& node)
+{
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ flushRegisters();
+ callOperation(
+ operationNewFunction, resultGPR, m_jit.codeBlock()->functionDecl(node.functionDeclIndex()));
+ cellResult(resultGPR, m_compileIndex);
+}
+
+void SpeculativeJIT::compileNewFunctionExpression(Node& node)
+{
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ flushRegisters();
+ callOperation(
+ operationNewFunctionExpression,
+ resultGPR,
+ m_jit.codeBlock()->functionExpr(node.functionExprIndex()));
+ cellResult(resultGPR, m_compileIndex);
+}
+
} } // namespace JSC::DFG
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 5d95b064f..1744a03f3 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -104,9 +104,7 @@ public:
return m_nodeIndex;
}
-#ifndef NDEBUG
void dump(FILE* out) const;
-#endif
private:
static NodeIndex nodeIndexFromKind(ValueSourceKind kind)
@@ -454,7 +452,7 @@ private:
ASSERT(info.gpr() == target);
if (node.hasConstant()) {
ASSERT(isBooleanConstant(nodeIndex));
- m_jit.move(Imm32(valueOfBooleanConstant(nodeIndex)), target);
+ m_jit.move(TrustedImm32(valueOfBooleanConstant(nodeIndex)), target);
} else
m_jit.load32(JITCompiler::payloadFor(spillMe), target);
#endif
@@ -466,7 +464,7 @@ private:
if (node.hasConstant()) {
JSValue value = valueOfJSConstant(nodeIndex);
ASSERT(value.isCell());
- m_jit.move(ImmPtr(value.asCell()), target);
+ m_jit.move(TrustedImmPtr(value.asCell()), target);
} else
m_jit.loadPtr(JITCompiler::payloadFor(spillMe), target);
return;
@@ -481,9 +479,12 @@ private:
ASSERT(registerFormat & DataFormatJS);
#if USE(JSVALUE64)
ASSERT(info.gpr() == target);
- if (node.hasConstant())
- m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), target);
- else if (info.spillFormat() == DataFormatInteger) {
+ if (node.hasConstant()) {
+ if (valueOfJSConstant(nodeIndex).isCell())
+ m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex).asTrustedImmPtr(), target);
+ else
+ m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), target);
+ } else if (info.spillFormat() == DataFormatInteger) {
ASSERT(registerFormat == DataFormatJSInteger);
m_jit.load32(JITCompiler::payloadFor(spillMe), target);
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, target);
@@ -875,20 +876,21 @@ private:
}
}
- // Returns the node index of the branch node if peephole is okay, NoNode otherwise.
- NodeIndex detectPeepHoleBranch()
+ // Returns the index of the branch node if peephole is okay, UINT_MAX otherwise.
+ unsigned detectPeepHoleBranch()
{
- NodeIndex lastNodeIndex = m_jit.graph().m_blocks[m_block]->end - 1;
+ BasicBlock* block = m_jit.graph().m_blocks[m_block].get();
// Check that no intervening nodes will be generated.
- for (NodeIndex index = m_compileIndex + 1; index < lastNodeIndex; ++index) {
- if (at(index).shouldGenerate())
- return NoNode;
+ for (unsigned index = m_indexInBlock + 1; index < block->size() - 1; ++index) {
+ NodeIndex nodeIndex = block->at(index);
+ if (at(nodeIndex).shouldGenerate())
+ return UINT_MAX;
}
// Check if the lastNode is a branch on this node.
- Node& lastNode = at(lastNodeIndex);
- return lastNode.op == Branch && lastNode.child1().index() == m_compileIndex ? lastNodeIndex : NoNode;
+ Node& lastNode = at(block->last());
+ return lastNode.op == Branch && lastNode.child1().index() == m_compileIndex ? block->size() - 1 : UINT_MAX;
}
void nonSpeculativeValueToNumber(Node&);
@@ -1124,7 +1126,7 @@ private:
}
JITCompiler::Call callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants)
{
- m_jit.setupArgumentsWithExecState(Imm32(startConstant), Imm32(numConstants));
+ m_jit.setupArgumentsWithExecState(TrustedImm32(startConstant), TrustedImm32(numConstants));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg result, GPRReg arg1, void* pointer)
@@ -1162,6 +1164,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EC operation, GPRReg result, JSCell* cell)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(C_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
@@ -1182,14 +1189,14 @@ private:
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
- JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, MacroAssembler::Imm32 imm)
+ JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, MacroAssembler::TrustedImm32 imm)
{
- m_jit.setupArgumentsWithExecState(arg1, MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))));
+ m_jit.setupArgumentsWithExecState(arg1, MacroAssembler::TrustedImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))));
return appendCallWithExceptionCheckSetResult(operation, result);
}
- JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, MacroAssembler::Imm32 imm, GPRReg arg2)
+ JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, MacroAssembler::TrustedImm32 imm, GPRReg arg2)
{
- m_jit.setupArgumentsWithExecState(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))), arg2);
+ m_jit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))), arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
@@ -1197,6 +1204,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(V_DFGOperation_EC operation, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1, GPRReg arg2, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(pointer));
@@ -1287,7 +1299,7 @@ private:
}
JITCompiler::Call callOperation(J_DFGOperation_EJP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, void* pointer)
{
- m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, ImmPtr(pointer));
+ m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, TrustedImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2)
@@ -1330,6 +1342,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_DFGOperation_EC operation, GPRReg result, JSCell* cell)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(C_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
@@ -1350,12 +1367,12 @@ private:
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
- JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, MacroAssembler::Imm32 imm)
+ JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, MacroAssembler::TrustedImm32 imm)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, imm, TrustedImm32(JSValue::Int32Tag));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
- JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, MacroAssembler::Imm32 imm, GPRReg arg2Tag, GPRReg arg2Payload)
+ JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, MacroAssembler::TrustedImm32 imm, GPRReg arg2Tag, GPRReg arg2Payload)
{
m_jit.setupArgumentsWithExecState(imm, TrustedImm32(JSValue::Int32Tag), arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
@@ -1365,6 +1382,11 @@ private:
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(V_DFGOperation_EC operation, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheck(operation);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(pointer));
@@ -1620,7 +1642,7 @@ private:
{
if (!DFG_ENABLE_EDGE_CODE_VERIFICATION)
return;
- m_jit.move(Imm32(destination), GPRInfo::regT0);
+ m_jit.move(TrustedImm32(destination), GPRInfo::regT0);
}
void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
@@ -1693,6 +1715,7 @@ private:
void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
void compileAdd(Node&);
void compileArithSub(Node&);
+ void compileArithNegate(Node&);
void compileArithMul(Node&);
void compileArithMod(Node&);
void compileSoftModulo(Node&);
@@ -1715,14 +1738,18 @@ private:
void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness, TypedArrayRounding = TruncateRounding);
void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements);
void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements);
+ void compileNewFunctionNoCheck(Node& node);
+ void compileNewFunctionExpression(Node& node);
- // It is acceptable to have structure be equal to scratch, so long as you're fine
- // with the structure GPR being clobbered.
- template<typename T>
- void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
+ template <typename ClassType, bool destructor, typename StructureType>
+ void emitAllocateBasicJSObject(StructureType structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
{
- MarkedAllocator* allocator = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(sizeof(JSFinalObject));
-
+ MarkedAllocator* allocator = 0;
+ if (destructor)
+ allocator = &m_jit.globalData()->heap.allocatorForObjectWithDestructor(sizeof(ClassType));
+ else
+ allocator = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(sizeof(ClassType));
+
m_jit.loadPtr(&allocator->m_firstFreeCell, resultGPR);
slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
@@ -1738,14 +1765,22 @@ private:
m_jit.storePtr(scratchGPR, &allocator->m_firstFreeCell);
// Initialize the object's classInfo pointer
- m_jit.storePtr(MacroAssembler::TrustedImmPtr(&JSFinalObject::s_info), MacroAssembler::Address(resultGPR, JSCell::classInfoOffset()));
+ m_jit.storePtr(MacroAssembler::TrustedImmPtr(&ClassType::s_info), MacroAssembler::Address(resultGPR, JSCell::classInfoOffset()));
// Initialize the object's inheritorID.
m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
// Initialize the object's property storage pointer.
m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
- m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
+ m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, ClassType::offsetOfPropertyStorage()));
+ }
+
+ // It is acceptable to have structure be equal to scratch, so long as you're fine
+ // with the structure GPR being clobbered.
+ template<typename T>
+ void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
+ {
+ return emitAllocateBasicJSObject<JSFinalObject, false>(structure, resultGPR, scratchGPR, slowPath);
}
#if USE(JSVALUE64)
@@ -1849,6 +1884,7 @@ private:
// The current node being generated.
BlockIndex m_block;
NodeIndex m_compileIndex;
+ unsigned m_indexInBlock;
// Virtual and physical register maps.
Vector<GenerationInfo, 32> m_generationInfo;
RegisterBank<GPRInfo> m_gprs;
@@ -2482,6 +2518,7 @@ inline SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
: m_compileOkay(true)
, m_jit(jit)
, m_compileIndex(0)
+ , m_indexInBlock(0)
, m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
, m_blockHeads(jit.graph().m_blocks.size())
, m_arguments(jit.codeBlock()->numParameters())
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 8c4d8c030..b6814229c 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -652,14 +652,17 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(NodeUse operand, NodeIndex
bool SpeculativeJIT::nonSpeculativeCompareNull(Node& node, NodeUse operand, bool invert)
{
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+
ASSERT(node.adjustedRefCount() == 1);
nonSpeculativePeepholeBranchNull(operand, branchNodeIndex, invert);
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
@@ -947,7 +950,7 @@ void SpeculativeJIT::emitCall(Node& node)
m_jit.storePtr(resultPayloadGPR, callFramePayloadSlot(RegisterFile::ScopeChain));
m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), callFrameTagSlot(RegisterFile::ScopeChain));
- m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
+ m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin;
CallBeginToken token = m_jit.beginJSCall();
@@ -958,12 +961,12 @@ void SpeculativeJIT::emitCall(Node& node)
slowPath.link(&m_jit);
- m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
m_jit.poke(GPRInfo::argumentGPR0);
token = m_jit.beginCall();
JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction);
m_jit.addFastExceptionCheck(slowCall, codeOrigin, token);
- m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
+ m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
token = m_jit.beginJSCall();
JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR);
m_jit.notifyCall(theCall, codeOrigin, token);
@@ -1387,10 +1390,10 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf
GPRReg resultPayloadGPR = resultPayload.gpr();
MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
- m_jit.move(Imm32(1), resultPayloadGPR);
+ m_jit.move(TrustedImm32(1), resultPayloadGPR);
MacroAssembler::Jump done = m_jit.jump();
falseCase.link(&m_jit);
- m_jit.move(Imm32(0), resultPayloadGPR);
+ m_jit.move(TrustedImm32(0), resultPayloadGPR);
done.link(&m_jit);
booleanResult(resultPayloadGPR, m_compileIndex);
@@ -1414,9 +1417,9 @@ void SpeculativeJIT::compileDoubleCompare(Node& node, MacroAssembler::DoubleCond
SpeculateDoubleOperand op2(this, node.child2());
GPRTemporary resultPayload(this);
- m_jit.move(Imm32(1), resultPayload.gpr());
+ m_jit.move(TrustedImm32(1), resultPayload.gpr());
MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
- m_jit.move(Imm32(0), resultPayload.gpr());
+ m_jit.move(TrustedImm32(0), resultPayload.gpr());
trueCase.link(&m_jit);
booleanResult(resultPayload.gpr(), m_compileIndex);
@@ -1637,7 +1640,7 @@ void SpeculativeJIT::emitBranch(Node& node)
void SpeculativeJIT::compile(Node& node)
{
- NodeType op = node.op;
+ NodeType op = static_cast<NodeType>(node.op);
switch (op) {
case JSConstant:
@@ -1654,54 +1657,59 @@ void SpeculativeJIT::compile(Node& node)
AbstractValue& value = block()->valuesAtHead.operand(node.local());
// If we have no prediction for this local, then don't attempt to compile.
- if (prediction == PredictNone) {
+ if (prediction == PredictNone || value.isClear()) {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
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(m_compileIndex, node.refCount(), result.fpr());
- break;
- }
+ if (!m_jit.graph().isCaptured(node.local())) {
+ 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(m_compileIndex, node.refCount(), result.fpr());
+ break;
+ }
- GPRTemporary result(this);
- if (isInt32Prediction(prediction)) {
- 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(m_compileIndex, node.refCount(), result.gpr());
- break;
- }
+ if (isInt32Prediction(prediction)) {
+ GPRTemporary result(this);
+ m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
- if (isArrayPrediction(prediction) || isByteArrayPrediction(prediction)) {
- 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(m_compileIndex, node.refCount(), result.gpr());
+ break;
+ }
- // 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(m_compileIndex, node.refCount(), result.gpr());
- break;
- }
+ if (isArrayPrediction(prediction) || isByteArrayPrediction(prediction)) {
+ 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(m_compileIndex, node.refCount(), result.gpr());
+ break;
+ }
- if (isBooleanPrediction(prediction)) {
- m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
+ if (isBooleanPrediction(prediction)) {
+ 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(m_compileIndex, node.refCount(), result.gpr());
- break;
+ // 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(m_compileIndex, node.refCount(), result.gpr());
+ break;
+ }
}
+ GPRTemporary result(this);
GPRTemporary tag(this);
m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
m_jit.load32(JITCompiler::tagFor(node.local()), tag.gpr());
@@ -1712,7 +1720,12 @@ void SpeculativeJIT::compile(Node& node)
m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
- DataFormat format = isCellPrediction(value.m_type) ? DataFormatJSCell : DataFormatJS;
+ DataFormat format;
+ if (isCellPrediction(value.m_type)
+ && !m_jit.graph().isCaptured(node.local()))
+ format = DataFormatJSCell;
+ else
+ format = DataFormatJS;
m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), tag.gpr(), result.gpr(), format);
break;
}
@@ -1733,53 +1746,65 @@ void SpeculativeJIT::compile(Node& node)
m_codeOriginForOSR = nextNode.codeOrigin;
- if (node.variableAccessData()->shouldUseDoubleFormat()) {
- SpeculateDoubleOperand value(this, node.child1());
- m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
- noResult(m_compileIndex);
- // Indicate that it's no longer necessary to retrieve the value of
- // this bytecode variable from registers or other locations in the register file,
- // but that it is stored as a double.
- valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
- } else {
+ if (!m_jit.graph().isCaptured(node.local())) {
+ if (node.variableAccessData()->shouldUseDoubleFormat()) {
+ SpeculateDoubleOperand value(this, node.child1());
+ m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
+ noResult(m_compileIndex);
+ // Indicate that it's no longer necessary to retrieve the value of
+ // this bytecode variable from registers or other locations in the register file,
+ // but that it is stored as a double.
+ valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
+ break;
+ }
PredictedType predictedType = node.variableAccessData()->prediction();
if (m_generationInfo[at(node.child1()).virtualRegister()].registerFormat() == DataFormatDouble) {
DoubleOperand value(this, node.child1());
m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- } else if (isInt32Prediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
+ break;
+ }
+ if (isInt32Prediction(predictedType)) {
SpeculateIntegerOperand value(this, node.child1());
m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- } else if (isArrayPrediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile);
+ break;
+ }
+ if (isArrayPrediction(predictedType)) {
SpeculateCellOperand cell(this, node.child1());
GPRReg cellGPR = cell.gpr();
if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- } else if (isByteArrayPrediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
+ break;
+ }
+ if (isByteArrayPrediction(predictedType)) {
SpeculateCellOperand cell(this, node.child1());
GPRReg cellGPR = cell.gpr();
if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSByteArray::s_info)));
m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- } else if (isBooleanPrediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
+ break;
+ }
+ if (isBooleanPrediction(predictedType)) {
SpeculateBooleanOperand value(this, node.child1());
m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- } else {
- JSValueOperand value(this, node.child1());
- m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local()));
- m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node.local()));
- noResult(m_compileIndex);
+ valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile);
+ break;
}
-
- // Indicate that it's no longer necessary to retrieve the value of
- // this bytecode variable from registers or other locations in the register file.
- valueSourceReferenceForOperand(node.local()) = ValueSource::forPrediction(predictedType);
}
+ JSValueOperand value(this, node.child1());
+ m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local()));
+ m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node.local()));
+ noResult(m_compileIndex);
+ valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile);
break;
}
@@ -1863,6 +1888,10 @@ void SpeculativeJIT::compile(Node& node)
compileArithSub(node);
break;
+ case ArithNegate:
+ compileArithNegate(node);
+ break;
+
case ArithMul:
compileArithMul(node);
break;
@@ -1951,7 +1980,7 @@ void SpeculativeJIT::compile(Node& node)
case ArithAbs: {
if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) {
SpeculateIntegerOperand op1(this, node.child1());
- GPRTemporary result(this);
+ GPRTemporary result(this, op1);
GPRTemporary scratch(this);
m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
@@ -2350,7 +2379,7 @@ void SpeculativeJIT::compile(Node& node)
// Code to handle put beyond array bounds.
silentSpillAllRegisters(scratchReg);
- callOperation(operationPutByValBeyondArrayBounds, baseReg, propertyReg, valueTagReg, valuePayloadReg);
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, baseReg, propertyReg, valueTagReg, valuePayloadReg);
silentFillAllRegisters(scratchReg);
JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
@@ -2514,10 +2543,10 @@ void SpeculativeJIT::compile(Node& node)
m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- m_jit.add32(Imm32(1), storageLengthGPR);
+ m_jit.add32(TrustedImm32(1), storageLengthGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- m_jit.add32(Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
- m_jit.move(Imm32(JSValue::Int32Tag), storageGPR);
+ m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
MacroAssembler::Jump done = m_jit.jump();
@@ -2554,7 +2583,7 @@ void SpeculativeJIT::compile(Node& node)
MacroAssembler::Jump emptyArrayCase = m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
- m_jit.sub32(Imm32(1), storageLengthGPR);
+ m_jit.sub32(TrustedImm32(1), storageLengthGPR);
MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
@@ -2563,11 +2592,11 @@ void SpeculativeJIT::compile(Node& node)
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- MacroAssembler::Jump holeCase = m_jit.branch32(MacroAssembler::Equal, Imm32(JSValue::EmptyValueTag), valueTagGPR);
+ MacroAssembler::Jump holeCase = m_jit.branch32(MacroAssembler::Equal, TrustedImm32(JSValue::EmptyValueTag), valueTagGPR);
m_jit.store32(TrustedImm32(JSValue::EmptyValueTag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
- m_jit.sub32(MacroAssembler::Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ m_jit.sub32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
MacroAssembler::JumpList done;
@@ -2575,8 +2604,8 @@ void SpeculativeJIT::compile(Node& node)
holeCase.link(&m_jit);
emptyArrayCase.link(&m_jit);
- m_jit.move(MacroAssembler::Imm32(jsUndefined().tag()), valueTagGPR);
- m_jit.move(MacroAssembler::Imm32(jsUndefined().payload()), valuePayloadGPR);
+ m_jit.move(MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR);
+ m_jit.move(MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR);
done.append(m_jit.jump());
slowCase.link(&m_jit);
@@ -3384,7 +3413,7 @@ void SpeculativeJIT::compile(Node& node)
case Phi:
case Flush:
- ASSERT_NOT_REACHED();
+ break;
case Breakpoint:
#if ENABLE(DEBUG_WITH_BREAKPOINT)
@@ -3466,6 +3495,77 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case CreateActivation: {
+ JSValueOperand value(this, node.child1());
+ GPRTemporary result(this, value, false);
+
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.move(valuePayloadGPR, resultGPR);
+
+ JITCompiler::Jump alreadyCreated = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
+
+ silentSpillAllRegisters(resultGPR);
+ callOperation(operationCreateActivation, resultGPR);
+ silentFillAllRegisters(resultGPR);
+
+ alreadyCreated.link(&m_jit);
+
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
+ case TearOffActivation: {
+ JSValueOperand value(this, node.child1());
+
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
+
+ JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
+
+ silentSpillAllRegisters(InvalidGPRReg);
+ callOperation(operationTearOffActivation, valuePayloadGPR);
+ silentFillAllRegisters(InvalidGPRReg);
+
+ notCreated.link(&m_jit);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case NewFunctionNoCheck:
+ compileNewFunctionNoCheck(node);
+ break;
+
+ case NewFunction: {
+ JSValueOperand value(this, node.child1());
+ GPRTemporary result(this, value, false);
+
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.move(valuePayloadGPR, resultGPR);
+
+ JITCompiler::Jump alreadyCreated = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
+
+ silentSpillAllRegisters(resultGPR);
+ callOperation(
+ operationNewFunction, resultGPR, m_jit.codeBlock()->functionDecl(node.functionDeclIndex()));
+ silentFillAllRegisters(resultGPR);
+
+ alreadyCreated.link(&m_jit);
+
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
+ case NewFunctionExpression:
+ compileNewFunctionExpression(node);
+ break;
+
case ForceOSRExit: {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
break;
@@ -3478,10 +3578,11 @@ void SpeculativeJIT::compile(Node& node)
case InlineStart:
case Nop:
+ case LastNodeType:
ASSERT_NOT_REACHED();
break;
}
-
+
if (!m_compileOkay)
return;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 6d375f81f..1597b1674 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -57,7 +57,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat
} else {
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
}
} else if (info.spillFormat() == DataFormatInteger) {
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
@@ -141,7 +141,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
// FIXME: should not be reachable?
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
info.fillJSValue(gpr, DataFormatJS);
unlock(gpr);
@@ -283,7 +283,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex)
} else {
ASSERT(isJSConstant(nodeIndex));
JSValue jsValue = valueOfJSConstant(nodeIndex);
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
info.fillJSValue(gpr, DataFormatJS);
}
@@ -628,14 +628,17 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(NodeUse operand, NodeIndex
bool SpeculativeJIT::nonSpeculativeCompareNull(Node& node, NodeUse operand, bool invert)
{
- NodeIndex branchNodeIndex = detectPeepHoleBranch();
- if (branchNodeIndex != NoNode) {
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+
ASSERT(node.adjustedRefCount() == 1);
nonSpeculativePeepholeBranchNull(operand, branchNodeIndex, invert);
use(node.child1());
use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
m_compileIndex = branchNodeIndex;
return true;
@@ -808,15 +811,21 @@ void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node& node, NodeIndex branch
JITCompiler::Jump twoCellsCase = m_jit.branchTestPtr(JITCompiler::Zero, resultGPR, GPRInfo::tagMaskRegister);
- JITCompiler::Jump numberCase = m_jit.branchTestPtr(JITCompiler::NonZero, resultGPR, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump leftOK = m_jit.branchPtr(JITCompiler::AboveOrEqual, arg1GPR, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump leftDouble = m_jit.branchTestPtr(JITCompiler::NonZero, arg1GPR, GPRInfo::tagTypeNumberRegister);
+ leftOK.link(&m_jit);
+ JITCompiler::Jump rightOK = m_jit.branchPtr(JITCompiler::AboveOrEqual, arg2GPR, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump rightDouble = m_jit.branchTestPtr(JITCompiler::NonZero, arg2GPR, GPRInfo::tagTypeNumberRegister);
+ rightOK.link(&m_jit);
- branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1GPR, arg2GPR, taken);
+ branchPtr(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1GPR, arg2GPR, taken);
jump(notTaken, ForceJump);
twoCellsCase.link(&m_jit);
branchPtr(JITCompiler::Equal, arg1GPR, arg2GPR, invert ? notTaken : taken);
- numberCase.link(&m_jit);
+ leftDouble.link(&m_jit);
+ rightDouble.link(&m_jit);
silentSpillAllRegisters(resultGPR);
callOperation(operationCompareStrictEq, resultGPR, arg1GPR, arg2GPR);
@@ -865,9 +874,14 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert)
JITCompiler::Jump twoCellsCase = m_jit.branchTestPtr(JITCompiler::Zero, resultGPR, GPRInfo::tagMaskRegister);
- JITCompiler::Jump numberCase = m_jit.branchTestPtr(JITCompiler::NonZero, resultGPR, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump leftOK = m_jit.branchPtr(JITCompiler::AboveOrEqual, arg1GPR, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump leftDouble = m_jit.branchTestPtr(JITCompiler::NonZero, arg1GPR, GPRInfo::tagTypeNumberRegister);
+ leftOK.link(&m_jit);
+ JITCompiler::Jump rightOK = m_jit.branchPtr(JITCompiler::AboveOrEqual, arg2GPR, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump rightDouble = m_jit.branchTestPtr(JITCompiler::NonZero, arg2GPR, GPRInfo::tagTypeNumberRegister);
+ rightOK.link(&m_jit);
- m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1GPR, arg2GPR, resultGPR);
+ m_jit.comparePtr(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1GPR, arg2GPR, resultGPR);
JITCompiler::Jump done1 = m_jit.jump();
@@ -878,7 +892,8 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert)
JITCompiler::Jump done2 = m_jit.jump();
- numberCase.link(&m_jit);
+ leftDouble.link(&m_jit);
+ rightDouble.link(&m_jit);
notEqualCase.link(&m_jit);
silentSpillAllRegisters(resultGPR);
@@ -948,7 +963,7 @@ void SpeculativeJIT::emitCall(Node& node)
m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultGPR);
m_jit.storePtr(resultGPR, callFrameSlot(RegisterFile::ScopeChain));
- m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
+ m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin;
CallBeginToken token = m_jit.beginJSCall();
@@ -959,11 +974,11 @@ void SpeculativeJIT::emitCall(Node& node)
slowPath.link(&m_jit);
- m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
token = m_jit.beginCall();
JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction);
m_jit.addFastExceptionCheck(slowCall, codeOrigin, token);
- m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
+ m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
token = m_jit.beginJSCall();
JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR);
m_jit.notifyCall(theCall, codeOrigin, token);
@@ -1461,10 +1476,10 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf
speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
- m_jit.move(Imm32(ValueTrue), resultGPR);
+ m_jit.move(TrustedImm32(ValueTrue), resultGPR);
MacroAssembler::Jump done = m_jit.jump();
falseCase.link(&m_jit);
- m_jit.move(Imm32(ValueFalse), resultGPR);
+ m_jit.move(TrustedImm32(ValueFalse), resultGPR);
done.link(&m_jit);
jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
@@ -1491,7 +1506,7 @@ void SpeculativeJIT::compileDoubleCompare(Node& node, MacroAssembler::DoubleCond
m_jit.move(TrustedImm32(ValueTrue), result.gpr());
MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
- m_jit.xorPtr(Imm32(true), result.gpr());
+ m_jit.xorPtr(TrustedImm32(true), result.gpr());
trueCase.link(&m_jit);
jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
@@ -1577,7 +1592,7 @@ void SpeculativeJIT::compileLogicalNot(Node& node)
GPRTemporary result(this);
m_jit.move(TrustedImm32(ValueFalse), result.gpr());
MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
- m_jit.xor32(Imm32(true), result.gpr());
+ m_jit.xor32(TrustedImm32(true), result.gpr());
nonZero.link(&m_jit);
jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
return;
@@ -1699,18 +1714,18 @@ void SpeculativeJIT::emitBranch(Node& node)
bool predictBoolean = isBooleanPrediction(m_jit.getPrediction(node.child1()));
if (predictBoolean) {
- branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false))), notTaken);
- branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true))), taken);
+ branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), notTaken);
+ branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), taken);
speculationCheck(BadType, JSValueRegs(valueGPR), node.child1(), m_jit.jump());
value.use();
} else {
- branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0))), notTaken);
+ branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImmPtr(JSValue::encode(jsNumber(0))), notTaken);
branchPtr(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister, taken);
if (!predictBoolean) {
- branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false))), notTaken);
- branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true))), taken);
+ branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), notTaken);
+ branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), taken);
}
value.use();
@@ -1729,7 +1744,7 @@ void SpeculativeJIT::emitBranch(Node& node)
void SpeculativeJIT::compile(Node& node)
{
- NodeType op = node.op;
+ NodeType op = static_cast<NodeType>(node.op);
switch (op) {
case JSConstant:
@@ -1751,27 +1766,30 @@ void SpeculativeJIT::compile(Node& node)
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(m_compileIndex, node.refCount(), result.fpr());
- break;
- }
-
- GPRTemporary result(this);
- if (isInt32Prediction(value.m_type)) {
- 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(m_compileIndex, node.refCount(), result.gpr());
- break;
+ if (!m_jit.graph().isCaptured(node.local())) {
+ 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(m_compileIndex, node.refCount(), result.fpr());
+ break;
+ }
+
+ if (isInt32Prediction(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(m_compileIndex, node.refCount(), result.gpr());
+ break;
+ }
}
+ GPRTemporary result(this);
m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.gpr());
// Like jsValueResult, but don't useChildren - our children are phi nodes,
@@ -1780,7 +1798,9 @@ void SpeculativeJIT::compile(Node& node)
m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
DataFormat format;
- if (isCellPrediction(value.m_type))
+ if (m_jit.graph().isCaptured(node.local()))
+ format = DataFormatJS;
+ else if (isCellPrediction(value.m_type))
format = DataFormatJSCell;
else if (isBooleanPrediction(value.m_type))
format = DataFormatJSBoolean;
@@ -1817,48 +1837,60 @@ void SpeculativeJIT::compile(Node& node)
// OSR exit, would not be visible to the old JIT in any way.
m_codeOriginForOSR = nextNode.codeOrigin;
- if (node.variableAccessData()->shouldUseDoubleFormat()) {
- SpeculateDoubleOperand value(this, node.child1());
- m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
- noResult(m_compileIndex);
- // Indicate that it's no longer necessary to retrieve the value of
- // this bytecode variable from registers or other locations in the register file,
- // but that it is stored as a double.
- valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
- } else {
+ if (!m_jit.graph().isCaptured(node.local())) {
+ if (node.variableAccessData()->shouldUseDoubleFormat()) {
+ SpeculateDoubleOperand value(this, node.child1());
+ m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
+ noResult(m_compileIndex);
+ // Indicate that it's no longer necessary to retrieve the value of
+ // this bytecode variable from registers or other locations in the register file,
+ // but that it is stored as a double.
+ valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
+ break;
+ }
+
PredictedType predictedType = node.variableAccessData()->prediction();
if (isInt32Prediction(predictedType)) {
SpeculateIntegerOperand value(this, node.child1());
m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
noResult(m_compileIndex);
- } else if (isArrayPrediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile);
+ break;
+ }
+ if (isArrayPrediction(predictedType)) {
SpeculateCellOperand cell(this, node.child1());
GPRReg cellGPR = cell.gpr();
if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- } else if (isByteArrayPrediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
+ break;
+ }
+ if (isByteArrayPrediction(predictedType)) {
SpeculateCellOperand cell(this, node.child1());
GPRReg cellGPR = cell.gpr();
if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSByteArray::s_info)));
m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- } else if (isBooleanPrediction(predictedType)) {
+ valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
+ break;
+ }
+ if (isBooleanPrediction(predictedType)) {
SpeculateBooleanOperand boolean(this, node.child1());
m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local()));
noResult(m_compileIndex);
- } else {
- JSValueOperand value(this, node.child1());
- m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));
- noResult(m_compileIndex);
+ valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile);
+ break;
}
-
- // Indicate that it's no longer necessary to retrieve the value of
- // this bytecode variable from registers or other locations in the register file.
- valueSourceReferenceForOperand(node.local()) = ValueSource::forPrediction(predictedType);
}
+
+ JSValueOperand value(this, node.child1());
+ m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));
+ noResult(m_compileIndex);
+
+ valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile);
break;
}
@@ -1942,6 +1974,10 @@ void SpeculativeJIT::compile(Node& node)
compileArithSub(node);
break;
+ case ArithNegate:
+ compileArithNegate(node);
+ break;
+
case ArithMul:
compileArithMul(node);
break;
@@ -2007,7 +2043,7 @@ void SpeculativeJIT::compile(Node& node)
case ArithAbs: {
if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) {
SpeculateIntegerOperand op1(this, node.child1());
- GPRTemporary result(this, op1);
+ GPRTemporary result(this);
GPRTemporary scratch(this);
m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
@@ -2389,7 +2425,7 @@ void SpeculativeJIT::compile(Node& node)
// Code to handle put beyond array bounds.
silentSpillAllRegisters(scratchReg);
- callOperation(operationPutByValBeyondArrayBounds, baseReg, propertyReg, valueReg);
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, baseReg, propertyReg, valueReg);
silentFillAllRegisters(scratchReg);
JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
@@ -2549,9 +2585,9 @@ void SpeculativeJIT::compile(Node& node)
m_jit.storePtr(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
- m_jit.add32(Imm32(1), storageLengthGPR);
+ m_jit.add32(TrustedImm32(1), storageLengthGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
- m_jit.add32(Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
MacroAssembler::Jump done = m_jit.jump();
@@ -2587,7 +2623,7 @@ void SpeculativeJIT::compile(Node& node)
MacroAssembler::Jump emptyArrayCase = m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
- m_jit.sub32(Imm32(1), storageLengthGPR);
+ m_jit.sub32(TrustedImm32(1), storageLengthGPR);
MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
@@ -2598,7 +2634,7 @@ void SpeculativeJIT::compile(Node& node)
MacroAssembler::Jump holeCase = m_jit.branchTestPtr(MacroAssembler::Zero, valueGPR);
m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
- m_jit.sub32(MacroAssembler::Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ m_jit.sub32(MacroAssembler::TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
MacroAssembler::JumpList done;
@@ -3358,9 +3394,9 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- case Phi:
case Flush:
- ASSERT_NOT_REACHED();
+ case Phi:
+ break;
case Breakpoint:
#if ENABLE(DEBUG_WITH_BREAKPOINT)
@@ -3434,6 +3470,73 @@ void SpeculativeJIT::compile(Node& node)
jsValueResult(resultGPR, m_compileIndex);
break;
}
+
+ case CreateActivation: {
+ JSValueOperand value(this, node.child1());
+ GPRTemporary result(this, value);
+
+ GPRReg valueGPR = value.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.move(valueGPR, resultGPR);
+
+ JITCompiler::Jump alreadyCreated = m_jit.branchTestPtr(JITCompiler::NonZero, resultGPR);
+
+ silentSpillAllRegisters(resultGPR);
+ callOperation(operationCreateActivation, resultGPR);
+ silentFillAllRegisters(resultGPR);
+
+ alreadyCreated.link(&m_jit);
+
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
+ case TearOffActivation: {
+ JSValueOperand value(this, node.child1());
+ GPRReg valueGPR = value.gpr();
+
+ JITCompiler::Jump notCreated = m_jit.branchTestPtr(JITCompiler::Zero, valueGPR);
+
+ silentSpillAllRegisters(InvalidGPRReg);
+ callOperation(operationTearOffActivation, valueGPR);
+ silentFillAllRegisters(InvalidGPRReg);
+
+ notCreated.link(&m_jit);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case NewFunctionNoCheck:
+ compileNewFunctionNoCheck(node);
+ break;
+
+ case NewFunction: {
+ JSValueOperand value(this, node.child1());
+ GPRTemporary result(this, value);
+
+ GPRReg valueGPR = value.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.move(valueGPR, resultGPR);
+
+ JITCompiler::Jump alreadyCreated = m_jit.branchTestPtr(JITCompiler::NonZero, resultGPR);
+
+ silentSpillAllRegisters(resultGPR);
+ callOperation(
+ operationNewFunction, resultGPR, m_jit.codeBlock()->functionDecl(node.functionDeclIndex()));
+ silentFillAllRegisters(resultGPR);
+
+ alreadyCreated.link(&m_jit);
+
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
+ case NewFunctionExpression:
+ compileNewFunctionExpression(node);
+ break;
case ForceOSRExit: {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
@@ -3449,6 +3552,10 @@ void SpeculativeJIT::compile(Node& node)
case Nop:
ASSERT_NOT_REACHED();
break;
+
+ case LastNodeType:
+ ASSERT_NOT_REACHED();
+ break;
}
if (!m_compileOkay)
diff --git a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
index c0b9fae65..255003612 100644
--- a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp
@@ -48,39 +48,62 @@ public:
dataLog("\n");
#endif
ScoreBoard scoreBoard(m_graph, m_graph.m_preservedVars);
- unsigned sizeExcludingPhiNodes = m_graph.m_blocks.last()->end;
- for (size_t i = 0; i < sizeExcludingPhiNodes; ++i) {
- Node& node = m_graph[i];
-
- if (!node.shouldGenerate())
- continue;
+ scoreBoard.assertClear();
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ bool needsNewLine = false;
+#endif
+ for (size_t blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ for (size_t indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+ NodeIndex nodeIndex = block->at(indexInBlock);
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ if (needsNewLine)
+ dataLog("\n");
+ dataLog(" @%u:", nodeIndex);
+ needsNewLine = true;
+#endif
+ Node& node = m_graph[nodeIndex];
- // GetLocal nodes are effectively phi nodes in the graph, referencing
- // results from prior blocks.
- if (node.op != GetLocal) {
- // First, call use on all of the current node's children, then
- // allocate a VirtualRegister for this node. We do so in this
- // order so that if a child is on its last use, and a
- // VirtualRegister is freed, then it may be reused for node.
- if (node.op & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
- scoreBoard.use(m_graph.m_varArgChildren[childIdx]);
- } else {
- scoreBoard.use(node.child1());
- scoreBoard.use(node.child2());
- scoreBoard.use(node.child3());
+ if (!node.shouldGenerate() || node.op == Phi || node.op == Flush)
+ continue;
+
+ // GetLocal nodes are effectively phi nodes in the graph, referencing
+ // results from prior blocks.
+ if (node.op != GetLocal) {
+ // First, call use on all of the current node's children, then
+ // allocate a VirtualRegister for this node. We do so in this
+ // order so that if a child is on its last use, and a
+ // VirtualRegister is freed, then it may be reused for node.
+ if (node.flags & NodeHasVarArgs) {
+ for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
+ scoreBoard.use(m_graph.m_varArgChildren[childIdx]);
+ } else {
+ scoreBoard.use(node.child1());
+ scoreBoard.use(node.child2());
+ scoreBoard.use(node.child3());
+ }
}
- }
- if (!node.hasResult())
- continue;
+ if (!node.hasResult())
+ continue;
- node.setVirtualRegister(scoreBoard.allocate());
- // 'mustGenerate' nodes have their useCount artificially elevated,
- // call use now to account for this.
- if (node.mustGenerate())
- scoreBoard.use(i);
+ VirtualRegister virtualRegister = scoreBoard.allocate();
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Assigning virtual register %u to node %u.",
+ virtualRegister, nodeIndex);
+#endif
+ node.setVirtualRegister(virtualRegister);
+ // 'mustGenerate' nodes have their useCount artificially elevated,
+ // call use now to account for this.
+ if (node.mustGenerate())
+ scoreBoard.use(nodeIndex);
+ }
+ scoreBoard.assertClear();
}
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ if (needsNewLine)
+ dataLog("\n");
+#endif
// 'm_numCalleeRegisters' is the number of locals and temporaries allocated
// for the function (and checked for on entry). Since we perform a new and