/*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
namespace JSC { namespace DFG {
+static const bool verbose = false;
+
InPlaceAbstractState::InPlaceAbstractState(Graph& graph)
: m_graph(graph)
, m_variables(m_graph.m_codeBlock->numParameters(), graph.m_localVars)
forNode(basicBlock->at(i)).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) {
+ for (; iter != end; ++iter)
forNode(iter->key) = iter->value;
- if (iter->value.hasClobberableState())
- m_haveStructures = true;
- }
}
-
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)
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))
+ switch (format) {
+ case FlushedInt32:
root->valuesAtHead.argument(i).setType(SpecInt32);
- else if (isBooleanSpeculation(prediction))
+ break;
+ case FlushedBoolean:
root->valuesAtHead.argument(i).setType(SpecBoolean);
- else if (isCellSpeculation(prediction))
- root->valuesAtHead.argument(i).setType(SpecCell);
- else
+ break;
+ case FlushedCell:
+ root->valuesAtHead.argument(i).setType(m_graph, SpecCell);
+ break;
+ case FlushedJSValue:
root->valuesAtHead.argument(i).makeHeapTop();
+ 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) {
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();
block->valuesAtHead.local(i).clear();
block->valuesAtTail.local(i).clear();
}
- if (m_graph.m_form == SSA)
- continue;
- 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) {
- int operand = m_graph.m_mustHandleAbstractValues.operandForIndex(i);
- Node* node = block->variablesAtHead.operand(operand);
- if (!node)
- continue;
- AbstractValue value = m_graph.m_mustHandleAbstractValues[i];
- AbstractValue& abstractValue = block->valuesAtHead.operand(operand);
- VariableAccessData* variable = node->variableAccessData();
- FlushFormat format = variable->flushFormat();
- abstractValue.merge(value);
- abstractValue.fixTypeForRepresentation(resultFor(format));
- }
- block->cfaShouldRevisit = true;
}
if (m_graph.m_form == SSA) {
for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
bool changed = false;
- if (mergeMode != DontMerge || !ASSERT_DISABLED) {
+ if ((mergeMode != DontMerge) || !ASSERT_DISABLED) {
+ changed |= checkAndSet(block->cfaStructureClobberStateAtTail, m_structureClobberState);
+
switch (m_graph.m_form) {
case ThreadedCPS: {
for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
m_block = 0;
m_isValid = false;
m_branchDirection = InvalidBranchDirection;
+ m_structureClobberState = StructuresAreWatched;
}
bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
AbstractValue source;
- 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 not using the
- // GetLocal's result.
-
+ switch (node->op()) {
+ case Phi:
+ case SetArgument:
+ case PhantomLocal:
+ case Flush:
+ // The block transfers the value from head to tail.
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;
+ 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)
- RELEASE_ASSERT(!(source.m_type & ~SpecFullDouble));
- 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;
- }
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
if (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) {
HashSet<Node*>::iterator end = to->ssa->liveAtHead.end();
for (; iter != end; ++iter) {
Node* node = *iter;
+ if (verbose)
+ dataLog(" Merging for ", node, ": from ", from->ssa->valuesAtTail.find(node)->value, " to ", to->ssa->valuesAtHead.find(node)->value, "\n");
changed |= to->ssa->valuesAtHead.find(node)->value.merge(
from->ssa->valuesAtTail.find(node)->value);
+ if (verbose)
+ dataLog(" Result: ", to->ssa->valuesAtHead.find(node)->value, "\n");
}
break;
}
if (!to->cfaHasVisited)
changed = true;
+ if (verbose)
+ dataLog(" Will revisit: ", changed, "\n");
to->cfaShouldRevisit |= changed;
return changed;
inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
{
- Node* terminal = basicBlock->last();
+ Node* terminal = basicBlock->terminal();
ASSERT(terminal->isTerminal());