void InPlaceAbstractState::beginBasicBlock(BasicBlock* basicBlock) { ASSERT(!m_block); ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->valuesAtHead.numberOfLocals()); ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals()); ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals()); for (size_t i = 0; i < basicBlock->size(); i++) forNode(basicBlock->at(i)).clear(); m_variables = basicBlock->valuesAtHead; 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; } basicBlock->cfaShouldRevisit = false; basicBlock->cfaHasVisited = true; m_block = basicBlock; m_isValid = true; m_foundConstants = false; m_branchDirection = InvalidBranchDirection; m_structureClobberState = basicBlock->cfaStructureClobberStateAtHead; }
bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node) { if (!node) return false; AbstractValue source; 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 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; } // 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; }
bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node) { if (!node) return false; 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. source = inVariable; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Transfering "); source.dump(WTF::dataFile()); dataLogF(" from last access due to captured variable.\n"); #endif } else { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" It's live, node @%u.\n", node->index()); #endif switch (node->op()) { case Phi: case SetArgument: case PhantomLocal: case Flush: // The block transfers the value from head to tail. source = inVariable; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Transfering "); source.dump(WTF::dataFile()); dataLogF(" from head to tail.\n"); #endif break; case GetLocal: // The block refines the value with additional speculations. source = forNode(node); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Refining to "); source.dump(WTF::dataFile()); dataLogF("\n"); #endif break; case SetLocal: // The block sets the variable, and potentially refines it, both // before and after setting it. if (node->variableAccessData()->shouldUseDoubleFormat()) { // FIXME: This unnecessarily loses precision. source.setType(SpecDouble); } else source = forNode(node->child1()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Setting to "); source.dump(WTF::dataFile()); dataLogF("\n"); #endif 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. #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Not changed!\n"); #endif return false; } // 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; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Changed!\n"); #endif return true; }
bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode) { ASSERT(m_block); BasicBlock* block = m_block; // Save the block for successor merging. block->cfaFoundConstants = m_foundConstants; block->cfaDidFinish = m_isValid; block->cfaBranchDirection = m_branchDirection; if (!m_isValid) { 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) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Merging state for argument %zu.\n", argument); #endif 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) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Merging state for local %zu.\n", local); #endif AbstractValue& destination = block->valuesAtTail.local(local); changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local)); } 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; } default: RELEASE_ASSERT_NOT_REACHED(); } } ASSERT(mergeMode != DontMerge || !changed); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Branch direction = %s\n", branchDirectionToString(m_branchDirection)); #endif reset(); if (mergeMode != MergeToSuccessors) return changed; return mergeToSuccessors(block); }
static MemSource forNode(const Node &node) { return forNode(node.physicalId()); }