Ignore:
Timestamp:
May 19, 2018, 3:00:21 PM (7 years ago)
Author:
[email protected]
Message:

DFG should inline InstanceOf ICs
https://bugs.webkit.org/show_bug.cgi?id=185695

Reviewed by Yusuke Suzuki.

Source/JavaScriptCore:

This teaches the DFG how to inline InstanceOf ICs into a MatchStructure node. This can then
be folded to a CheckStructure + JSConstant.

In the process of testing this, I found a bug where LICM was not hoisting things that
depended on ExtraOSREntryLocal because that might return SpecEmpty. I fixed that by teaching
LICM how to materialize CheckNotEmpty on demand whenever HoistingFailed.

This is a ~5% speed-up on boyer.

~2x speed-up on the instanceof-always-hit-one, instanceof-always-hit-two, and
instanceof-sometimes-hit microbenchmarks.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::appendVariant):
(JSC::GetByIdStatus::filter):

  • bytecode/GetByIdStatus.h:

(JSC::GetByIdStatus::operator bool const):
(JSC::GetByIdStatus::operator! const): Deleted.

  • bytecode/GetByIdVariant.h:

(JSC::GetByIdVariant::operator bool const):
(JSC::GetByIdVariant::operator! const): Deleted.

  • bytecode/ICStatusUtils.h: Added.

(JSC::appendICStatusVariant):
(JSC::filterICStatusVariants):

  • bytecode/InstanceOfStatus.cpp: Added.

(JSC::InstanceOfStatus::appendVariant):
(JSC::InstanceOfStatus::computeFor):
(JSC::InstanceOfStatus::computeForStubInfo):
(JSC::InstanceOfStatus::commonPrototype const):
(JSC::InstanceOfStatus::filter):

  • bytecode/InstanceOfStatus.h: Added.

(JSC::InstanceOfStatus::InstanceOfStatus):
(JSC::InstanceOfStatus::state const):
(JSC::InstanceOfStatus::isSet const):
(JSC::InstanceOfStatus::operator bool const):
(JSC::InstanceOfStatus::isSimple const):
(JSC::InstanceOfStatus::takesSlowPath const):
(JSC::InstanceOfStatus::numVariants const):
(JSC::InstanceOfStatus::variants const):
(JSC::InstanceOfStatus::at const):
(JSC::InstanceOfStatus::operator[] const):

  • bytecode/InstanceOfVariant.cpp: Added.

(JSC::InstanceOfVariant::InstanceOfVariant):
(JSC::InstanceOfVariant::attemptToMerge):
(JSC::InstanceOfVariant::dump const):
(JSC::InstanceOfVariant::dumpInContext const):

  • bytecode/InstanceOfVariant.h: Added.

(JSC::InstanceOfVariant::InstanceOfVariant):
(JSC::InstanceOfVariant::operator bool const):
(JSC::InstanceOfVariant::structureSet const):
(JSC::InstanceOfVariant::structureSet):
(JSC::InstanceOfVariant::conditionSet const):
(JSC::InstanceOfVariant::prototype const):
(JSC::InstanceOfVariant::isHit const):

  • bytecode/StructureStubInfo.cpp:

(JSC::StructureStubInfo::StructureStubInfo):

  • bytecode/StructureStubInfo.h:

(JSC::StructureStubInfo::considerCaching):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

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

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGGraph.cpp:

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

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

(JSC::DFG::LICMPhase::attemptHoist):

  • dfg/DFGNode.cpp:

(JSC::DFG::Node::remove):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasMatchStructureData):
(JSC::DFG::Node::matchStructureData):

  • dfg/DFGNodeType.h:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileMatchStructure):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileMatchStructure):

Source/WTF:

I found myself needing a way to represent bottom/false/true/top, so I created it.

  • WTF.xcodeproj/project.pbxproj:
  • wtf/BooleanLattice.h: Added.

(WTF::lubBooleanLattice):
(WTF::printInternal):

  • wtf/CMakeLists.txt:
File:
1 edited

Legend:

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

    r231185 r232000  
    11/*
    2  * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    265265       
    266266        m_state.initializeTo(data.preHeader);
    267         if (!safeToExecute(m_state, m_graph, node)) {
    268             if (verbose) {
    269                 dataLog(
    270                     "    Not hoisting ", node, " because it isn't safe to execute.\n");
    271             }
    272             return false;
    273         }
    274        
     267
    275268        NodeOrigin originalOrigin = node->origin;
     269        bool canSpeculateBlindly = !m_graph.hasGlobalExitSite(originalOrigin.semantic, HoistingFailed);
    276270
    277271        // NOTE: We could just use BackwardsDominators here directly, since we already know that the
     
    281275            && !m_graph.m_controlEquivalenceAnalysis->dominatesEquivalently(data.preHeader, fromBlock);
    282276       
    283         if (addsBlindSpeculation
    284             && m_graph.hasGlobalExitSite(originalOrigin.semantic, HoistingFailed)) {
     277        if (addsBlindSpeculation && !canSpeculateBlindly) {
    285278            if (verbose) {
    286279                dataLog(
     
    292285        }
    293286       
     287        // For abstract interpretation, these are in the reverse order that they appear in this
     288        // vector.
     289        Vector<Node*, 2> hoistedNodesReverse;
     290        hoistedNodesReverse.append(node);
     291
     292        NodeOrigin terminalOrigin = data.preHeader->terminal()->origin;
     293       
     294        auto insertHoistedNode = [&] (Node* node) {
     295            data.preHeader->insertBeforeTerminal(node);
     296            node->owner = data.preHeader;
     297            node->origin = terminalOrigin.withSemantic(node->origin.semantic);
     298            node->origin.wasHoisted |= addsBlindSpeculation;
     299        };
     300       
     301        if (!safeToExecute(m_state, m_graph, node)) {
     302            // See if we can rescue the situation by inserting blind speculations.
     303            bool ignoreEmptyChildren = true;
     304            if (canSpeculateBlindly
     305                && safeToExecute(m_state, m_graph, node, ignoreEmptyChildren)) {
     306                if (verbose) {
     307                    dataLog(
     308                        "    Rescuing hoisting by inserting empty checks.\n");
     309                }
     310                m_graph.doToChildren(
     311                    node,
     312                    [&] (Edge& edge) {
     313                        if (!(m_state.forNode(edge).m_type & SpecEmpty))
     314                            return;
     315                       
     316                        Node* check = m_graph.addNode(CheckNotEmpty, originalOrigin, Edge(edge.node(), UntypedUse));
     317                        insertHoistedNode(check);
     318                        hoistedNodesReverse.append(check);
     319                    });
     320            } else {
     321                if (verbose) {
     322                    dataLog(
     323                        "    Not hoisting ", node, " because it isn't safe to execute.\n");
     324                }
     325                return false;
     326            }
     327        }
     328       
    294329        if (verbose) {
    295330            dataLog(
     
    298333        }
    299334
    300         data.preHeader->insertBeforeTerminal(node);
    301         node->owner = data.preHeader;
    302         NodeOrigin terminalOrigin = data.preHeader->terminal()->origin;
    303         node->origin = terminalOrigin.withSemantic(node->origin.semantic);
    304         node->origin.wasHoisted |= addsBlindSpeculation;
     335        insertHoistedNode(node);
    305336       
    306337        // We can trust what AI proves about edge proof statuses when hoisting to the preheader.
    307338        m_state.trustEdgeProofs();
    308339        m_state.initializeTo(data.preHeader);
    309         m_interpreter.execute(node);
     340        for (unsigned i = hoistedNodesReverse.size(); i--;)
     341            m_interpreter.execute(hoistedNodesReverse[i]);
    310342        // However, when walking various inner loops below, the proof status of
    311343        // an edge may be trivially true, even if it's not true in the preheader
     
    341373                continue;
    342374            m_state.initializeTo(subPreHeader);
    343             m_interpreter.execute(node);
     375            for (unsigned i = hoistedNodesReverse.size(); i--;)
     376                m_interpreter.execute(hoistedNodesReverse[i]);
    344377        }
    345378
Note: See TracChangeset for help on using the changeset viewer.