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, 140 insertions, 116 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
index e5d88d2d5..468c68f84 100644
--- a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 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,12 @@
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
#include "GetByIdStatus.h"
-#include "JSCInlines.h"
+#include "Operations.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)
@@ -60,18 +58,36 @@ 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) {
- for (auto& entry : basicBlock->ssa->valuesAtHead)
- forNode(entry.key) = entry.value;
+ 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;
+ }
}
+
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)
@@ -90,44 +106,37 @@ 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();
-
- 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();
- }
+ 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;
}
- switch (format) {
- case FlushedInt32:
+ SpeculatedType prediction =
+ node->variableAccessData()->argumentAwarePrediction();
+ if (isInt32Speculation(prediction))
root->valuesAtHead.argument(i).setType(SpecInt32);
- break;
- case FlushedBoolean:
+ else if (isBooleanSpeculation(prediction))
root->valuesAtHead.argument(i).setType(SpecBoolean);
- 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;
- }
+ else if (isCellSpeculation(prediction))
+ root->valuesAtHead.argument(i).setType(SpecCell);
+ else
+ root->valuesAtHead.argument(i).makeHeapTop();
}
for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
- root->valuesAtHead.local(i).clear();
+ Node* node = root->variablesAtHead.local(i);
+ if (node && node->variableAccessData()->isCaptured())
+ root->valuesAtHead.local(i).makeHeapTop();
+ else
+ root->valuesAtHead.local(i).clear();
root->valuesAtTail.local(i).clear();
}
for (BlockIndex blockIndex = 1 ; blockIndex < m_graph.numBlocks(); ++blockIndex) {
@@ -138,8 +147,6 @@ 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();
@@ -148,6 +155,16 @@ 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) {
@@ -160,7 +177,7 @@ void InPlaceAbstractState::initialize()
}
}
-bool InPlaceAbstractState::endBasicBlock()
+bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode)
{
ASSERT(m_block);
@@ -175,41 +192,48 @@ bool InPlaceAbstractState::endBasicBlock()
return false;
}
- bool changed = checkAndSet(block->cfaStructureClobberStateAtTail, m_structureClobberState);
+ bool changed = false;
- 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));
+ 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;
}
-
- 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));
+
+ 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;
}
- 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));
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
}
- break;
}
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
-
+
+ ASSERT(mergeMode != DontMerge || !changed);
+
reset();
+ if (mergeMode != MergeToSuccessors)
+ return changed;
+
return mergeToSuccessors(block);
}
@@ -218,7 +242,6 @@ void InPlaceAbstractState::reset()
m_block = 0;
m_isValid = false;
m_branchDirection = InvalidBranchDirection;
- m_structureClobberState = StructuresAreWatched;
}
bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
@@ -228,31 +251,46 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
AbstractValue source;
- switch (node->op()) {
- case Phi:
- case SetArgument:
- case PhantomLocal:
- case Flush:
- // The block transfers the value from head to tail.
+ 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;
- break;
+ } else {
+ 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)
- 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) {
+ 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;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
if (destination == source) {
@@ -270,17 +308,11 @@ 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) {
@@ -298,16 +330,13 @@ 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]);
-
- 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(
+
+ 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);
-
- if (verbose)
- dataLog(" Result: ", entry.value, "\n");
}
break;
}
@@ -320,8 +349,6 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
if (!to->cfaHasVisited)
changed = true;
- if (verbose)
- dataLog(" Will revisit: ", changed, "\n");
to->cfaShouldRevisit |= changed;
return changed;
@@ -329,23 +356,23 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to)
inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
{
- Node* terminal = basicBlock->terminal();
+ Node* terminal = basicBlock->last();
ASSERT(terminal->isTerminal());
switch (terminal->op()) {
case Jump: {
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
- return merge(basicBlock, terminal->targetBlock());
+ return merge(basicBlock, terminal->takenBlock());
}
case Branch: {
ASSERT(basicBlock->cfaBranchDirection != InvalidBranchDirection);
bool changed = false;
if (basicBlock->cfaBranchDirection != TakeFalse)
- changed |= merge(basicBlock, terminal->branchData()->taken.block);
+ changed |= merge(basicBlock, terminal->takenBlock());
if (basicBlock->cfaBranchDirection != TakeTrue)
- changed |= merge(basicBlock, terminal->branchData()->notTaken.block);
+ changed |= merge(basicBlock, terminal->notTakenBlock());
return changed;
}
@@ -354,16 +381,13 @@ 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.block);
+ bool changed = merge(basicBlock, data->fallThrough);
for (unsigned i = data->cases.size(); i--;)
- changed |= merge(basicBlock, data->cases[i].target.block);
+ changed |= merge(basicBlock, data->cases[i].target);
return changed;
}
case Return:
- case TailCall:
- case TailCallVarargs:
- case TailCallForwardVarargs:
case Unreachable:
ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
return false;