diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp | 320 |
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; |