Ignore:
Timestamp:
Aug 4, 2016, 12:33:21 PM (9 years ago)
Author:
[email protected]
Message:

[JSC] Speed up InPlaceAbstractState::endBasicBlock()
https://bugs.webkit.org/show_bug.cgi?id=160539

Patch by Benjamin Poulain <[email protected]> on 2016-08-04
Reviewed by Mark Lam.

This patch does small improvements to our handling
of value propagation to the successors.

One key insight is that using HashMap to map Nodes
to Value in valuesAtTail is too inefficient at the scale
we use it. Instead, I reuse our existing mapping
from every Node to its value, abstracted by forNode().

Since we are not going to use the mapping after endBasicBlock()
I can replace whatever we had there. The next beginBasicBlock()
will setup the new value as needed.

In endBasicBlock(), valuesAtTail is now a vector of all values live
at tail. For each node, I merge the previous live at tail with
the new value, then replace the value in the mapping.
Liveness Analysis guarantees we won't have duplicates there which
make the replacement sound.

Next, when propagating, I take the vector of values lives at head
and use the global node->value mapping to find its new abstract value.
Again, Liveness Analysis guarantees I won't find a value live at head
that was not replaced by the merging at tail of the predecessor.

All our live lists have become vectors instead of HashTable.
The mapping from Node to Value is always done by array indexing.
Same big-O, much smaller constant.

  • dfg/DFGAtTailAbstractState.cpp:

(JSC::DFG::AtTailAbstractState::AtTailAbstractState):
(JSC::DFG::AtTailAbstractState::createValueForNode):
(JSC::DFG::AtTailAbstractState::forNode):

  • dfg/DFGAtTailAbstractState.h:

I did not look much into this state, I just made it equivalent
to the previous mapping.

  • dfg/DFGBasicBlock.h:
  • dfg/DFGCFAPhase.cpp:

(JSC::DFG::CFAPhase::performBlockCFA):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGInPlaceAbstractState.cpp:

(JSC::DFG::InPlaceAbstractState::endBasicBlock):

(JSC::DFG::InPlaceAbstractState::mergeStateAtTail):
AbstractValue is big enough that we really don't want to copy it twice.

(JSC::DFG::InPlaceAbstractState::merge):
(JSC::DFG::setLiveValues): Deleted.

  • dfg/DFGInPlaceAbstractState.h:
  • dfg/DFGPhiChildren.h:

This is heap allocated by AbstractInterpreter. It should use fastMalloc().

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp

    r204112 r204130  
    11/*
    2  * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    8181}
    8282
    83 static void setLiveValues(HashMap<Node*, AbstractValue>& values, const Vector<Node*>& liveNodes)
    84 {
    85     values.clear();
    86     for (Node* node : liveNodes)
    87         values.add(node, AbstractValue());
    88 }
    89 
    9083static void setLiveValues(Vector<BasicBlock::SSAData::NodeAbstractValuePair>& values, const Vector<Node*>& live)
    9184{
     
    186179        return false;
    187180    }
    188    
    189     bool changed = checkAndSet(block->cfaStructureClobberStateAtTail, m_structureClobberState);
    190    
     181
     182    block->cfaStructureClobberStateAtTail = m_structureClobberState;
     183
    191184    switch (m_graph.m_form) {
    192185    case ThreadedCPS: {
    193186        for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) {
    194187            AbstractValue& destination = block->valuesAtTail.argument(argument);
    195             changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
     188            mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
    196189        }
    197190
    198191        for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
    199192            AbstractValue& destination = block->valuesAtTail.local(local);
    200             changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
     193            mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
    201194        }
    202195        break;
     
    205198    case SSA: {
    206199        for (size_t i = 0; i < block->valuesAtTail.size(); ++i)
    207             changed |= block->valuesAtTail[i].merge(m_variables[i]);
    208 
    209         for (Node* node : block->ssa->liveAtTail) {
    210             changed |= block->ssa->valuesAtTail.find(node)->value.merge(forNode(node));
     200            block->valuesAtTail[i].merge(m_variables[i]);
     201
     202        for (auto& valueAtTail : block->ssa->valuesAtTail) {
     203            AbstractValue& valueAtNode = forNode(valueAtTail.node);
     204            valueAtTail.value.merge(valueAtNode);
     205            valueAtNode = valueAtTail.value;
    211206        }
    212207        break;
     
    230225}
    231226
    232 bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
     227void InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node)
    233228{
    234229    if (!node)
    235         return false;
    236        
    237     AbstractValue source;
     230        return;
     231
     232    const AbstractValue* source = nullptr;
    238233   
    239234    switch (node->op()) {
     
    243238    case Flush:
    244239        // The block transfers the value from head to tail.
    245         source = inVariable;
     240        source = &inVariable;
    246241        break;
    247242           
    248243    case GetLocal:
    249244        // The block refines the value with additional speculations.
    250         source = forNode(node);
     245        source = &forNode(node);
    251246        break;
    252247           
     
    254249        // The block sets the variable, and potentially refines it, both
    255250        // before and after setting it.
    256         source = forNode(node->child1());
     251        source = &forNode(node->child1());
    257252        if (node->variableAccessData()->flushFormat() == FlushedDouble)
    258             RELEASE_ASSERT(!(source.m_type & ~SpecFullDouble));
     253            RELEASE_ASSERT(!(source->m_type & ~SpecFullDouble));
    259254        break;
    260255       
     
    263258        break;
    264259    }
    265    
    266     if (destination == source) {
    267         // Abstract execution did not change the output value of the variable, for this
    268         // basic block, on this iteration.
    269         return false;
    270     }
    271    
    272     // Abstract execution reached a new conclusion about the speculations reached about
    273     // this variable after execution of this basic block. Update the state, and return
    274     // true to indicate that the fixpoint must go on!
    275     destination = source;
    276     return true;
     260    destination = *source;
    277261}
    278262
     
    311295            Node* node = entry.node;
    312296            if (verbose)
    313                 dataLog("      Merging for ", node, ": from ", from->ssa->valuesAtTail.find(node)->value, " to ", entry.value, "\n");
    314             changed |= entry.value.merge(
    315                 from->ssa->valuesAtTail.find(node)->value);
     297                dataLog("      Merging for ", node, ": from ", forNode(node), " to ", entry.value, "\n");
     298#ifndef NDEBUG
     299            unsigned valueCountInFromBlock = 0;
     300            for (auto& fromBlockValueAtTail : from->ssa->valuesAtTail) {
     301                if (fromBlockValueAtTail.node == node) {
     302                    ASSERT(fromBlockValueAtTail.value == forNode(node));
     303                    ++valueCountInFromBlock;
     304                }
     305            }
     306            ASSERT(valueCountInFromBlock == 1);
     307#endif
     308
     309            changed |= entry.value.merge(forNode(node));
    316310
    317311            if (verbose)
Note: See TracChangeset for help on using the changeset viewer.