summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp320
1 files changed, 151 insertions, 169 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
index 468c68f84..1d20d1d4c 100644
--- a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,14 +31,17 @@
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
#include "GetByIdStatus.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "PutByIdStatus.h"
#include "StringObject.h"
namespace JSC { namespace DFG {
+static const bool verbose = false;
+
InPlaceAbstractState::InPlaceAbstractState(Graph& graph)
: m_graph(graph)
+ , m_abstractValues(*graph.m_abstractValuesCache)
, m_variables(m_graph.m_codeBlock->numParameters(), graph.m_localVars)
, m_block(0)
{
@@ -53,51 +56,39 @@ void InPlaceAbstractState::beginBasicBlock(BasicBlock* basicBlock)
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->valuesAtHead.numberOfLocals());
ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals());
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
+
+ m_abstractValues.resize();
- for (size_t i = 0; i < basicBlock->size(); i++)
- forNode(basicBlock->at(i)).clear();
+ for (size_t i = 0; i < basicBlock->size(); i++) {
+ NodeFlowProjection::forEach(
+ basicBlock->at(i), [&] (NodeFlowProjection nodeProjection) {
+ forNode(nodeProjection).clear();
+ });
+ }
m_variables = basicBlock->valuesAtHead;
- m_haveStructures = false;
- for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) {
- if (m_variables.argument(i).hasClobberableState()) {
- m_haveStructures = true;
- break;
- }
- }
- for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) {
- if (m_variables.local(i).hasClobberableState()) {
- m_haveStructures = true;
- break;
- }
- }
if (m_graph.m_form == SSA) {
- HashMap<Node*, AbstractValue>::iterator iter = basicBlock->ssa->valuesAtHead.begin();
- HashMap<Node*, AbstractValue>::iterator end = basicBlock->ssa->valuesAtHead.end();
- for (; iter != end; ++iter) {
- forNode(iter->key) = iter->value;
- if (iter->value.hasClobberableState())
- m_haveStructures = true;
+ for (NodeAbstractValuePair& entry : basicBlock->ssa->valuesAtHead) {
+ if (entry.node.isStillValid())
+ forNode(entry.node) = entry.value;
}
}
-
basicBlock->cfaShouldRevisit = false;
basicBlock->cfaHasVisited = true;
m_block = basicBlock;
m_isValid = true;
m_foundConstants = false;
m_branchDirection = InvalidBranchDirection;
+ m_structureClobberState = basicBlock->cfaStructureClobberStateAtHead;
}
-static void setLiveValues(HashMap<Node*, AbstractValue>& values, HashSet<Node*>& live)
+static void setLiveValues(Vector<NodeAbstractValuePair>& values, const Vector<NodeFlowProjection>& live)
{
- values.clear();
-
- HashSet<Node*>::iterator iter = live.begin();
- HashSet<Node*>::iterator end = live.end();
- for (; iter != end; ++iter)
- values.add(*iter, AbstractValue());
+ values.resize(0);
+ values.reserveCapacity(live.size());
+ for (NodeFlowProjection node : live)
+ values.uncheckedAppend(NodeAbstractValuePair { node, AbstractValue() });
}
void InPlaceAbstractState::initialize()
@@ -106,37 +97,44 @@ void InPlaceAbstractState::initialize()
root->cfaShouldRevisit = true;
root->cfaHasVisited = false;
root->cfaFoundConstants = false;
+ root->cfaStructureClobberStateAtHead = StructuresAreWatched;
+ root->cfaStructureClobberStateAtTail = StructuresAreWatched;
for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) {
root->valuesAtTail.argument(i).clear();
- if (m_graph.m_form == SSA) {
- root->valuesAtHead.argument(i).makeHeapTop();
- continue;
- }
-
- Node* node = root->variablesAtHead.argument(i);
- ASSERT(node->op() == SetArgument);
- if (!node->variableAccessData()->shouldUnboxIfPossible()) {
- root->valuesAtHead.argument(i).makeHeapTop();
- continue;
+
+ FlushFormat format;
+ if (m_graph.m_form == SSA)
+ format = m_graph.m_argumentFormats[i];
+ else {
+ Node* node = m_graph.m_arguments[i];
+ if (!node)
+ format = FlushedJSValue;
+ else {
+ ASSERT(node->op() == SetArgument);
+ format = node->variableAccessData()->flushFormat();
+ }
}
- SpeculatedType prediction =
- node->variableAccessData()->argumentAwarePrediction();
- if (isInt32Speculation(prediction))
- root->valuesAtHead.argument(i).setType(SpecInt32);
- else if (isBooleanSpeculation(prediction))
+ switch (format) {
+ case FlushedInt32:
+ root->valuesAtHead.argument(i).setType(SpecInt32Only);
+ break;
+ case FlushedBoolean:
root->valuesAtHead.argument(i).setType(SpecBoolean);
- else if (isCellSpeculation(prediction))
- root->valuesAtHead.argument(i).setType(SpecCell);
- else
- root->valuesAtHead.argument(i).makeHeapTop();
+ break;
+ case FlushedCell:
+ root->valuesAtHead.argument(i).setType(m_graph, SpecCell);
+ break;
+ case FlushedJSValue:
+ root->valuesAtHead.argument(i).makeBytecodeTop();
+ break;
+ default:
+ DFG_CRASH(m_graph, nullptr, "Bad flush format for argument");
+ break;
+ }
}
for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
- Node* node = root->variablesAtHead.local(i);
- if (node && node->variableAccessData()->isCaptured())
- root->valuesAtHead.local(i).makeHeapTop();
- else
- root->valuesAtHead.local(i).clear();
+ root->valuesAtHead.local(i).clear();
root->valuesAtTail.local(i).clear();
}
for (BlockIndex blockIndex = 1 ; blockIndex < m_graph.numBlocks(); ++blockIndex) {
@@ -147,6 +145,8 @@ void InPlaceAbstractState::initialize()
block->cfaShouldRevisit = false;
block->cfaHasVisited = false;
block->cfaFoundConstants = false;
+ block->cfaStructureClobberStateAtHead = StructuresAreWatched;
+ block->cfaStructureClobberStateAtTail = StructuresAreWatched;
for (size_t i = 0; i < block->valuesAtHead.numberOfArguments(); ++i) {
block->valuesAtHead.argument(i).clear();
block->valuesAtTail.argument(i).clear();
@@ -155,16 +155,6 @@ void InPlaceAbstractState::initialize()
block->valuesAtHead.local(i).clear();
block->valuesAtTail.local(i).clear();
}
- if (!block->isOSRTarget)
- continue;
- if (block->bytecodeBegin != m_graph.m_plan.osrEntryBytecodeIndex)
- continue;
- for (size_t i = 0; i < m_graph.m_mustHandleAbstractValues.size(); ++i) {
- AbstractValue value = m_graph.m_mustHandleAbstractValues[i];
- int operand = m_graph.m_mustHandleAbstractValues.operandForIndex(i);
- block->valuesAtHead.operand(operand).merge(value);
- }
- block->cfaShouldRevisit = true;
}
if (m_graph.m_form == SSA) {
for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
@@ -177,7 +167,7 @@ void InPlaceAbstractState::initialize()
}
}
-bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode)
+bool InPlaceAbstractState::endBasicBlock()
{
ASSERT(m_block);
@@ -191,49 +181,41 @@ bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode)
reset();
return false;
}
-
- bool changed = false;
-
- if (mergeMode != DontMerge || !ASSERT_DISABLED) {
- switch (m_graph.m_form) {
- case ThreadedCPS: {
- for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
- AbstractValue& destination = block->valuesAtTail.argument(argument);
- changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
- }
-
- for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
- AbstractValue& destination = block->valuesAtTail.local(local);
- changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
- }
- break;
+
+ block->cfaStructureClobberStateAtTail = m_structureClobberState;
+
+ switch (m_graph.m_form) {
+ case ThreadedCPS: {
+ for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
+ AbstractValue& destination = block->valuesAtTail.argument(argument);
+ mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
}
-
- case SSA: {
- for (size_t i = 0; i < block->valuesAtTail.size(); ++i)
- changed |= block->valuesAtTail[i].merge(m_variables[i]);
-
- HashSet<Node*>::iterator iter = block->ssa->liveAtTail.begin();
- HashSet<Node*>::iterator end = block->ssa->liveAtTail.end();
- for (; iter != end; ++iter) {
- Node* node = *iter;
- changed |= block->ssa->valuesAtTail.find(node)->value.merge(forNode(node));
- }
- break;
+
+ for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
+ AbstractValue& destination = block->valuesAtTail.local(local);
+ mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
}
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ case SSA: {
+ for (size_t i = 0; i < block->valuesAtTail.size(); ++i)
+ block->valuesAtTail[i].merge(m_variables[i]);
+
+ for (NodeAbstractValuePair& valueAtTail : block->ssa->valuesAtTail) {
+ AbstractValue& valueAtNode = forNode(valueAtTail.node);
+ valueAtTail.value.merge(valueAtNode);
+ valueAtNode = valueAtTail.value;
}
+ break;
}
-
- ASSERT(mergeMode != DontMerge || !changed);
-
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
reset();
- if (mergeMode != MergeToSuccessors)
- return changed;
-
return mergeToSuccessors(block);
}
@@ -242,77 +224,58 @@ void InPlaceAbstractState::reset()
m_block = 0;
m_isValid = false;
m_branchDirection = InvalidBranchDirection;
+ m_structureClobberState = StructuresAreWatched;
}
-bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
+void InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
{
if (!node)
- return false;
-
- AbstractValue source;
+ return;
+
+ const AbstractValue* source = nullptr;
- if (node->variableAccessData()->isCaptured()) {
- // If it's captured then we know that whatever value was stored into the variable last is the
- // one we care about. This is true even if the variable at tail is dead, which might happen if
- // the last thing we did to the variable was a GetLocal and then ended up now using the
- // GetLocal's result.
-
- source = inVariable;
- } else {
- switch (node->op()) {
- case Phi:
- case SetArgument:
- case PhantomLocal:
- case Flush:
- // The block transfers the value from head to tail.
- source = inVariable;
- break;
+ switch (node->op()) {
+ case Phi:
+ case SetArgument:
+ case PhantomLocal:
+ case Flush:
+ // The block transfers the value from head to tail.
+ source = &inVariable;
+ break;
- case GetLocal:
- // The block refines the value with additional speculations.
- source = forNode(node);
- break;
+ case GetLocal:
+ // The block refines the value with additional speculations.
+ source = &forNode(node);
+ break;
- case SetLocal:
- // The block sets the variable, and potentially refines it, both
- // before and after setting it.
- source = forNode(node->child1());
- if (node->variableAccessData()->flushFormat() == FlushedDouble) {
- ASSERT(!(source.m_type & ~SpecFullNumber));
- ASSERT(!!(source.m_type & ~SpecDouble) == !!(source.m_type & SpecMachineInt));
- if (!(source.m_type & ~SpecDouble)) {
- source.merge(SpecInt52AsDouble);
- source.filter(SpecDouble);
- }
- }
- break;
+ case SetLocal:
+ // The block sets the variable, and potentially refines it, both
+ // before and after setting it.
+ source = &forNode(node->child1());
+ if (node->variableAccessData()->flushFormat() == FlushedDouble)
+ RELEASE_ASSERT(!(source->m_type & ~SpecFullDouble));
+ break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
- }
-
- if (destination == source) {
- // Abstract execution did not change the output value of the variable, for this
- // basic block, on this iteration.
- return false;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
-
- // 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;
- return true;
+ destination = *source;
}
bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
{
+ if (verbose)
+ dataLog(" Merging from ", pointerDump(from), " to ", pointerDump(to), "\n");
ASSERT(from->variablesAtTail.numberOfArguments() == to->variablesAtHead.numberOfArguments());
ASSERT(from->variablesAtTail.numberOfLocals() == to->variablesAtHead.numberOfLocals());
bool changed = false;
+ changed |= checkAndSet(
+ to->cfaStructureClobberStateAtHead,
+ DFG::merge(from->cfaStructureClobberStateAtTail, to->cfaStructureClobberStateAtHead));
+
switch (m_graph.m_form) {
case ThreadedCPS: {
for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
@@ -330,13 +293,26 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
case SSA: {
for (size_t i = from->valuesAtTail.size(); i--;)
changed |= to->valuesAtHead[i].merge(from->valuesAtTail[i]);
-
- HashSet<Node*>::iterator iter = to->ssa->liveAtHead.begin();
- HashSet<Node*>::iterator end = to->ssa->liveAtHead.end();
- for (; iter != end; ++iter) {
- Node* node = *iter;
- changed |= to->ssa->valuesAtHead.find(node)->value.merge(
- from->ssa->valuesAtTail.find(node)->value);
+
+ for (NodeAbstractValuePair& entry : to->ssa->valuesAtHead) {
+ NodeFlowProjection node = entry.node;
+ if (verbose)
+ dataLog(" Merging for ", node, ": from ", forNode(node), " to ", entry.value, "\n");
+#ifndef NDEBUG
+ unsigned valueCountInFromBlock = 0;
+ for (NodeAbstractValuePair& fromBlockValueAtTail : from->ssa->valuesAtTail) {
+ if (fromBlockValueAtTail.node == node) {
+ ASSERT(fromBlockValueAtTail.value == forNode(node));
+ ++valueCountInFromBlock;
+ }
+ }
+ ASSERT(valueCountInFromBlock == 1);
+#endif
+
+ changed |= entry.value.merge(forNode(node));
+
+ if (verbose)
+ dataLog(" Result: ", entry.value, "\n");
}
break;
}
@@ -349,6 +325,8 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
if (!to->cfaHasVisited)
changed = true;
+ if (verbose)
+ dataLog(" Will revisit: ", changed, "\n");
to->cfaShouldRevisit |= changed;
return changed;
@@ -356,23 +334,23 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
{
- Node* terminal = basicBlock->last();
+ Node* terminal = basicBlock->terminal();
ASSERT(terminal->isTerminal());
switch (terminal->op()) {
case Jump: {
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
- return merge(basicBlock, terminal->takenBlock());
+ return merge(basicBlock, terminal->targetBlock());
}
case Branch: {
ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection);
bool changed = false;
if (basicBlock->cfaBranchDirection != TakeFalse)
- changed |= merge(basicBlock, terminal->takenBlock());
+ changed |= merge(basicBlock, terminal->branchData()->taken.block);
if (basicBlock->cfaBranchDirection != TakeTrue)
- changed |= merge(basicBlock, terminal->notTakenBlock());
+ changed |= merge(basicBlock, terminal->branchData()->notTaken.block);
return changed;
}
@@ -381,13 +359,17 @@ inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
// we're not. However I somehow doubt that this will ever be a big deal.
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
SwitchData* data = terminal->switchData();
- bool changed = merge(basicBlock, data->fallThrough);
+ bool changed = merge(basicBlock, data->fallThrough.block);
for (unsigned i = data->cases.size(); i--;)
- changed |= merge(basicBlock, data->cases[i].target);
+ changed |= merge(basicBlock, data->cases[i].target.block);
return changed;
}
case Return:
+ case TailCall:
+ case DirectTailCall:
+ case TailCallVarargs:
+ case TailCallForwardVarargs:
case Unreachable:
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
return false;