Ignore:
Timestamp:
Feb 24, 2014, 6:02:50 PM (11 years ago)
Author:
[email protected]
Message:

FTL should do polymorphic PutById inlining
https://bugs.webkit.org/show_bug.cgi?id=129210

Source/JavaScriptCore:

Reviewed by Mark Hahnenberg and Oliver Hunt.

This makes PutByIdStatus inform us about polymorphic cases by returning an array of
PutByIdVariants. The DFG now has a node called MultiPutByOffset that indicates a
selection of multiple inlined PutByIdVariants.

MultiPutByOffset is almost identical to MultiGetByOffset, which we added in
http://trac.webkit.org/changeset/164207.

This also does some FTL refactoring to make MultiPutByOffset share code with some nodes
that generate similar code.

1% speed-up on V8v7 due to splay improving by 6.8%. Splay does the thing where it
sometimes swaps field insertion order, creating fake polymorphism.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):
(JSC::PutByIdStatus::computeForStubInfo):
(JSC::PutByIdStatus::dump):

  • bytecode/PutByIdStatus.h:

(JSC::PutByIdStatus::PutByIdStatus):
(JSC::PutByIdStatus::isSimple):
(JSC::PutByIdStatus::numVariants):
(JSC::PutByIdStatus::variants):
(JSC::PutByIdStatus::at):
(JSC::PutByIdStatus::operator[]):

  • bytecode/PutByIdVariant.cpp: Added.

(JSC::PutByIdVariant::dump):
(JSC::PutByIdVariant::dumpInContext):

  • bytecode/PutByIdVariant.h: Added.

(JSC::PutByIdVariant::PutByIdVariant):
(JSC::PutByIdVariant::replace):
(JSC::PutByIdVariant::transition):
(JSC::PutByIdVariant::kind):
(JSC::PutByIdVariant::isSet):
(JSC::PutByIdVariant::operator!):
(JSC::PutByIdVariant::structure):
(JSC::PutByIdVariant::oldStructure):
(JSC::PutByIdVariant::newStructure):
(JSC::PutByIdVariant::structureChain):
(JSC::PutByIdVariant::offset):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::emitPrototypeChecks):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::emitPutById):
(JSC::DFG::ByteCodeParser::handlePutById):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::checkStructureElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::putStructureStoreElimination):
(JSC::DFG::CSEPhase::getByOffsetLoadElimination):
(JSC::DFG::CSEPhase::putByOffsetStoreElimination):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGraph.cpp:

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

  • dfg/DFGGraph.h:
  • dfg/DFGNode.cpp:

(JSC::DFG::MultiPutByOffsetData::writesStructures):
(JSC::DFG::MultiPutByOffsetData::reallocatesStorage):

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToPutByOffset):
(JSC::DFG::Node::hasMultiPutByOffsetData):
(JSC::DFG::Node::multiPutByOffsetData):

  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGTypeCheckHoistingPhase.cpp:

(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compilePutStructure):
(JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compilePutByOffset):
(JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
(JSC::FTL::LowerDFGToLLVM::loadProperty):
(JSC::FTL::LowerDFGToLLVM::storeProperty):
(JSC::FTL::LowerDFGToLLVM::addressOfProperty):
(JSC::FTL::LowerDFGToLLVM::storageForTransition):
(JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::emitStoreBarrier):

  • tests/stress/fold-multi-put-by-offset-to-put-by-offset.js: Added.
  • tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js: Added.
  • tests/stress/multi-put-by-offset-reallocation-cases.js: Added.

LayoutTests:

Reviewed by Mark Hahnenberg and Oliver Hunt.

Add a microbenchmark for polymorphic PutById.

  • js/regress/polymorphic-put-by-id-expected.txt: Added.
  • js/regress/polymorphic-put-by-id.html: Added.
  • js/regress/script-tests/polymorphic-put-by-id.js: Added.

(foo):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r164424 r164620  
    16411641            set.addAll(node->multiGetByOffsetData().variants[i].structureSet());
    16421642       
    1643         filter(value, set);
     1643        filter(node->child1(), set);
    16441644        forNode(node).makeHeapTop();
    16451645        break;
     
    16491649        break;
    16501650    }
    1651            
     1651       
     1652    case MultiPutByOffset: {
     1653        AbstractValue& value = forNode(node->child1());
     1654        ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
     1655
     1656        if (Structure* structure = value.bestProvenStructure()) {
     1657            bool done = false;
     1658            for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
     1659                const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
     1660                if (variant.oldStructure() != structure)
     1661                    continue;
     1662               
     1663                if (variant.kind() == PutByIdVariant::Replace) {
     1664                    filter(node->child1(), structure);
     1665                    m_state.setFoundConstants(true);
     1666                    m_state.setHaveStructures(true);
     1667                    done = true;
     1668                    break;
     1669                }
     1670               
     1671                ASSERT(variant.kind() == PutByIdVariant::Transition);
     1672                clobberStructures(clobberLimit);
     1673                forNode(node->child1()).set(m_graph, variant.newStructure());
     1674                m_state.setFoundConstants(true);
     1675                m_state.setHaveStructures(true);
     1676                done = true;
     1677                break;
     1678            }
     1679            if (done)
     1680                break;
     1681        }
     1682       
     1683        clobberStructures(clobberLimit);
     1684       
     1685        StructureSet newSet;
     1686        for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
     1687            const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
     1688            if (variant.kind() == PutByIdVariant::Replace) {
     1689                if (value.m_currentKnownStructure.contains(variant.structure()))
     1690                    newSet.addAll(variant.structure());
     1691                continue;
     1692            }
     1693            ASSERT(variant.kind() == PutByIdVariant::Transition);
     1694            if (value.m_currentKnownStructure.contains(variant.oldStructure()))
     1695                newSet.addAll(variant.newStructure());
     1696        }
     1697       
     1698        // Use filter(value, set) as a way of setting the structure set. This works because
     1699        // we would have already made the set be TOP before this. Filtering top is another
     1700        // way of setting.
     1701        filter(node->child1(), newSet);
     1702        break;
     1703    }
     1704   
    16521705    case CheckFunction: {
    16531706        JSValue value = forNode(node->child1()).value();
     
    16861739                m_graph.identifiers()[node->identifierNumber()],
    16871740                node->op() == PutByIdDirect);
    1688             if (status.isSimpleReplace()) {
    1689                 filter(node->child1(), structure);
    1690                 m_state.setFoundConstants(true);
    1691                 m_state.setHaveStructures(true);
    1692                 break;
    1693             }
    1694             if (status.isSimpleTransition()) {
    1695                 clobberStructures(clobberLimit);
    1696                 forNode(node->child1()).set(m_graph, status.newStructure());
    1697                 m_state.setHaveStructures(true);
    1698                 m_state.setFoundConstants(true);
    1699                 break;
     1741            if (status.isSimple() && status.numVariants() == 1) {
     1742                if (status[0].kind() == PutByIdVariant::Replace) {
     1743                    filter(node->child1(), structure);
     1744                    m_state.setFoundConstants(true);
     1745                    m_state.setHaveStructures(true);
     1746                    break;
     1747                }
     1748                if (status[0].kind() == PutByIdVariant::Transition) {
     1749                    clobberStructures(clobberLimit);
     1750                    forNode(node->child1()).set(m_graph, status[0].newStructure());
     1751                    m_state.setHaveStructures(true);
     1752                    m_state.setFoundConstants(true);
     1753                    break;
     1754                }
    17001755            }
    17011756        }
Note: See TracChangeset for help on using the changeset viewer.