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.cpp256
1 files changed, 116 insertions, 140 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
index 468c68f84..e5d88d2d5 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-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
@@ -31,12 +31,14 @@
#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_variables(m_graph.m_codeBlock->numParameters(), graph.m_localVars)
@@ -58,36 +60,18 @@ void InPlaceAbstractState::beginBasicBlock(BasicBlock* basicBlock)
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) {
- forNode(iter->key) = iter->value;
- if (iter->value.hasClobberableState())
- m_haveStructures = true;
- }
+ for (auto& entry : basicBlock->ssa->valuesAtHead)
+ forNode(entry.key) = 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)
@@ -106,37 +90,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))
+ 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
- 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 +138,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 +148,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 +160,7 @@ void InPlaceAbstractState::initialize()
}
}
-bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode)
+bool InPlaceAbstractState::endBasicBlock()
{
ASSERT(m_block);
@@ -192,48 +175,41 @@ bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode)
return false;
}
- bool changed = false;
+ bool changed = checkAndSet(block->cfaStructureClobberStateAtTail, m_structureClobberState);
- 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;
+ 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));
}
-
- 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);
+ changed |= 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)
+ 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;
}
-
- ASSERT(mergeMode != DontMerge || !changed);
-
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
reset();
- if (mergeMode != MergeToSuccessors)
- return changed;
-
return mergeToSuccessors(block);
}
@@ -242,6 +218,7 @@ void InPlaceAbstractState::reset()
m_block = 0;
m_isValid = false;
m_branchDirection = InvalidBranchDirection;
+ m_structureClobberState = StructuresAreWatched;
}
bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
@@ -251,46 +228,31 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
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 now 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) {
- 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;
- }
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
if (destination == source) {
@@ -308,11 +270,17 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
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 +298,16 @@ 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(
+
+ for (auto& entry : to->ssa->valuesAtHead) {
+ Node* node = entry.key;
+ if (verbose)
+ dataLog(" Merging for ", node, ": from ", from->ssa->valuesAtTail.find(node)->value, " to ", entry.value, "\n");
+ changed |= entry.value.merge(
from->ssa->valuesAtTail.find(node)->value);
+
+ if (verbose)
+ dataLog(" Result: ", entry.value, "\n");
}
break;
}
@@ -349,6 +320,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 +329,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 +354,16 @@ 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 TailCallVarargs:
+ case TailCallForwardVarargs:
case Unreachable:
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
return false;