Changeset 183207 in webkit


Ignore:
Timestamp:
Apr 23, 2015, 1:47:31 PM (10 years ago)
Author:
[email protected]
Message:

DFG should insert Phantoms late using BytecodeKills and block-local OSR availability
https://bugs.webkit.org/show_bug.cgi?id=143735

Reviewed by Geoffrey Garen.

We've always had bugs arising from the fact that we would MovHint something into a local,
and then fail to keep it alive. We would then try to keep things alive by putting Phantoms
on those Nodes that were MovHinted. But this became increasingly tricky. Given the
sophistication of the transformations we are doing today, this approach is just not sound
anymore.

This comprehensively fixes these bugs by having the DFG backend automatically insert
Phantoms just before codegen based on bytecode liveness. To make this practical, this also
makes it much faster to query bytecode liveness.

It's about as perf-neutral as it gets for a change that increases compiler work without
actually optimizing anything. Later changes will remove the old Phantom-preserving logic,
which should then speed us up. I can't really report concrete slow-down numbers because
they are low enough to basically be in the noise. For example, a 20-iteration run of
SunSpider yields "maybe 0.8% slower", whatever that means.

  • CMakeLists.txt:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/BytecodeLivenessAnalysis.cpp:

(JSC::BytecodeLivenessAnalysis::computeFullLiveness):

  • bytecode/FullBytecodeLiveness.h:

(JSC::FullBytecodeLiveness::getLiveness):

  • bytecode/VirtualRegister.h:

(JSC::VirtualRegister::operator+):
(JSC::VirtualRegister::operator-):

  • dfg/DFGForAllKills.h:

(JSC::DFG::forAllLiveNodesAtTail):
(JSC::DFG::forAllKilledOperands):
(JSC::DFG::forAllKilledNodesAtNodeIndex):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::isLiveInBytecode):
(JSC::DFG::Graph::localsLiveInBytecode):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::forAllLocalsLiveInBytecode):
(JSC::DFG::Graph::forAllLiveInBytecode):

  • dfg/DFGMayExit.cpp:

(JSC::DFG::mayExit):

  • dfg/DFGMovHintRemovalPhase.cpp:
  • dfg/DFGNodeType.h:
  • dfg/DFGPhantomInsertionPhase.cpp: Added.

(JSC::DFG::performPhantomInsertion):

  • dfg/DFGPhantomInsertionPhase.h: Added.
  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::compileInThreadImpl):

  • dfg/DFGScoreBoard.h:

(JSC::DFG::ScoreBoard::sortFree):
(JSC::DFG::ScoreBoard::assertClear):

  • dfg/DFGVirtualRegisterAllocationPhase.cpp:

(JSC::DFG::VirtualRegisterAllocationPhase::run):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::buildExitArguments):

  • tests/stress/phantom-inadequacy.js: Added.

(bar):
(baz):
(foo):

Location:
trunk/Source/JavaScriptCore
Files:
3 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r183199 r183207  
    204204    dfg/DFGOperations.cpp
    205205    dfg/DFGPhantomCanonicalizationPhase.cpp
     206    dfg/DFGPhantomInsertionPhase.cpp
    206207    dfg/DFGPhantomRemovalPhase.cpp
    207208    dfg/DFGPhase.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r183201 r183207  
     12015-04-22  Filip Pizlo  <[email protected]>
     2
     3        DFG should insert Phantoms late using BytecodeKills and block-local OSR availability
     4        https://bugs.webkit.org/show_bug.cgi?id=143735
     5
     6        Reviewed by Geoffrey Garen.
     7       
     8        We've always had bugs arising from the fact that we would MovHint something into a local,
     9        and then fail to keep it alive. We would then try to keep things alive by putting Phantoms
     10        on those Nodes that were MovHinted. But this became increasingly tricky. Given the
     11        sophistication of the transformations we are doing today, this approach is just not sound
     12        anymore.
     13       
     14        This comprehensively fixes these bugs by having the DFG backend automatically insert
     15        Phantoms just before codegen based on bytecode liveness. To make this practical, this also
     16        makes it much faster to query bytecode liveness.
     17       
     18        It's about as perf-neutral as it gets for a change that increases compiler work without
     19        actually optimizing anything. Later changes will remove the old Phantom-preserving logic,
     20        which should then speed us up. I can't really report concrete slow-down numbers because
     21        they are low enough to basically be in the noise. For example, a 20-iteration run of
     22        SunSpider yields "maybe 0.8% slower", whatever that means.
     23
     24        * CMakeLists.txt:
     25        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
     26        * JavaScriptCore.xcodeproj/project.pbxproj:
     27        * bytecode/BytecodeLivenessAnalysis.cpp:
     28        (JSC::BytecodeLivenessAnalysis::computeFullLiveness):
     29        * bytecode/FullBytecodeLiveness.h:
     30        (JSC::FullBytecodeLiveness::getLiveness):
     31        * bytecode/VirtualRegister.h:
     32        (JSC::VirtualRegister::operator+):
     33        (JSC::VirtualRegister::operator-):
     34        * dfg/DFGForAllKills.h:
     35        (JSC::DFG::forAllLiveNodesAtTail):
     36        (JSC::DFG::forAllKilledOperands):
     37        (JSC::DFG::forAllKilledNodesAtNodeIndex):
     38        * dfg/DFGGraph.cpp:
     39        (JSC::DFG::Graph::isLiveInBytecode):
     40        (JSC::DFG::Graph::localsLiveInBytecode):
     41        * dfg/DFGGraph.h:
     42        (JSC::DFG::Graph::forAllLocalsLiveInBytecode):
     43        (JSC::DFG::Graph::forAllLiveInBytecode):
     44        * dfg/DFGMayExit.cpp:
     45        (JSC::DFG::mayExit):
     46        * dfg/DFGMovHintRemovalPhase.cpp:
     47        * dfg/DFGNodeType.h:
     48        * dfg/DFGPhantomInsertionPhase.cpp: Added.
     49        (JSC::DFG::performPhantomInsertion):
     50        * dfg/DFGPhantomInsertionPhase.h: Added.
     51        * dfg/DFGPlan.cpp:
     52        (JSC::DFG::Plan::compileInThreadImpl):
     53        * dfg/DFGScoreBoard.h:
     54        (JSC::DFG::ScoreBoard::sortFree):
     55        (JSC::DFG::ScoreBoard::assertClear):
     56        * dfg/DFGVirtualRegisterAllocationPhase.cpp:
     57        (JSC::DFG::VirtualRegisterAllocationPhase::run):
     58        * ftl/FTLLowerDFGToLLVM.cpp:
     59        (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
     60        * tests/stress/phantom-inadequacy.js: Added.
     61        (bar):
     62        (baz):
     63        (foo):
     64
    1652015-04-23  Filip Pizlo  <[email protected]>
    266
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj

    r183161 r183207  
    448448    <ClCompile Include="..\dfg\DFGObjectMaterializationData.cpp" />
    449449    <ClCompile Include="..\dfg\DFGPhantomCanonicalizationPhase.cpp" />
     450    <ClCompile Include="..\dfg\DFGPhantomInsertionPhase.cpp" />
    450451    <ClCompile Include="..\dfg\DFGPhantomRemovalPhase.cpp" />
    451452    <ClCompile Include="..\dfg\DFGPhase.cpp" />
     
    11431144    <ClInclude Include="..\dfg\DFGOSRExitPreparation.h" />
    11441145    <ClInclude Include="..\dfg\DFGPhantomCanonicalizationPhase.h" />
     1146    <ClInclude Include="..\dfg\DFGPhantomInsertionPhase.h" />
    11451147    <ClInclude Include="..\dfg\DFGPhantomRemovalPhase.h" />
    11461148    <ClInclude Include="..\dfg\DFGPhase.h" />
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r183161 r183207  
    349349                0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
    350350                0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
     351                0F6237971AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */; };
     352                0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
    351353                0F63943F15C75F19006A597C /* DFGTypeCheckHoistingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
    352354                0F63944015C75F1D006A597C /* DFGTypeCheckHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */; };
     
    20842086                0F620170143FCD2F0068B77C /* DFGBasicBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBasicBlock.h; path = dfg/DFGBasicBlock.h; sourceTree = "<group>"; };
    20852087                0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessData.h; path = dfg/DFGVariableAccessData.h; sourceTree = "<group>"; };
     2088                0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPhantomInsertionPhase.cpp; path = dfg/DFGPhantomInsertionPhase.cpp; sourceTree = "<group>"; };
     2089                0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPhantomInsertionPhase.h; path = dfg/DFGPhantomInsertionPhase.h; sourceTree = "<group>"; };
    20862090                0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGTypeCheckHoistingPhase.cpp; path = dfg/DFGTypeCheckHoistingPhase.cpp; sourceTree = "<group>"; };
    20872091                0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGTypeCheckHoistingPhase.h; path = dfg/DFGTypeCheckHoistingPhase.h; sourceTree = "<group>"; };
     
    50255029                                0F7B365F197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp */,
    50265030                                0F7B3660197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h */,
     5031                                0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */,
     5032                                0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */,
    50275033                                0FBFDD02196C92BF007A5BFA /* DFGPhantomRemovalPhase.cpp */,
    50285034                                0FBFDD03196C92BF007A5BFA /* DFGPhantomRemovalPhase.h */,
     
    62216227                                BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */,
    62226228                                A72FFD64139985A800E5365A /* KeywordLookup.h in Headers */,
     6229                                0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */,
    62236230                                969A072A0ED1CE6900F1F681 /* Label.h in Headers */,
    62246231                                960097A60EBABB58007A7297 /* LabelScope.h in Headers */,
     
    74747481                                0FF729AD166AD35C000F5BA3 /* ProfilerBytecode.cpp in Sources */,
    74757482                                0FF729AE166AD35C000F5BA3 /* ProfilerBytecodes.cpp in Sources */,
     7483                                0F6237971AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp in Sources */,
    74767484                                0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */,
    74777485                                0FF729AF166AD35C000F5BA3 /* ProfilerCompilation.cpp in Sources */,
  • trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp

    r181993 r183207  
    238238    FastBitVector out;
    239239   
    240     result.m_map.clear();
     240    result.m_map.resize(m_codeBlock->instructions().size());
    241241   
    242242    for (unsigned i = m_basicBlocks.size(); i--;) {
     
    250250            unsigned bytecodeOffset = block->bytecodeOffsets()[i];
    251251            stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, out);
    252             result.m_map.add(bytecodeOffset, out);
     252            result.m_map[bytecodeOffset] = out;
    253253        }
    254254    }
  • trunk/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h

    r181993 r183207  
    3939    const FastBitVector& getLiveness(unsigned bytecodeIndex) const
    4040    {
    41         BytecodeToBitmapMap::const_iterator iter = m_map.find(bytecodeIndex);
    42         ASSERT(iter != m_map.end());
    43         return iter->value;
     41        return m_map[bytecodeIndex];
    4442    }
    4543   
     
    5250    friend class BytecodeLivenessAnalysis;
    5351   
    54     BytecodeToBitmapMap m_map;
     52    Vector<FastBitVector, 0, UnsafeVectorOverflow> m_map;
    5553};
    5654
  • trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h

    r181993 r183207  
    8383        return VirtualRegister(offset() - value);
    8484    }
     85    VirtualRegister operator+(VirtualRegister value) const
     86    {
     87        return VirtualRegister(offset() + value.offset());
     88    }
     89    VirtualRegister operator-(VirtualRegister value) const
     90    {
     91        return VirtualRegister(offset() - value.offset());
     92    }
    8593    VirtualRegister& operator+=(int value)
    8694    {
  • trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h

    r183094 r183207  
    5252   
    5353    AvailabilityMap& availabilityMap = block->ssa->availabilityAtTail;
    54     for (unsigned i = availabilityMap.m_locals.size(); i--;) {
    55         VirtualRegister reg = availabilityMap.m_locals.virtualRegisterForIndex(i);
    56        
    57         if (!graph.isLiveInBytecode(reg, block->terminal()->origin.forExit))
    58             continue;
    59        
    60         availabilityMap.closeStartingWithLocal(
    61             reg,
    62             [&] (Node* node) -> bool {
    63                 return seen.contains(node);
    64             },
    65             [&] (Node* node) -> bool {
    66                 if (!seen.add(node).isNewEntry)
    67                     return false;
    68                 functor(node);
    69                 return true;
    70             });
    71     }
    72 }
    73 
    74 template<typename Functor>
    75 void forAllKilledOperands(Graph& graph, CodeOrigin before, Node* nodeAfter, const Functor& functor)
    76 {
     54    graph.forAllLocalsLiveInBytecode(
     55        block->terminal()->origin.forExit,
     56        [&] (VirtualRegister reg) {
     57            availabilityMap.closeStartingWithLocal(
     58                reg,
     59                [&] (Node* node) -> bool {
     60                    return seen.contains(node);
     61                },
     62                [&] (Node* node) -> bool {
     63                    if (!seen.add(node).isNewEntry)
     64                        return false;
     65                    functor(node);
     66                    return true;
     67                });
     68        });
     69}
     70
     71// This tells you those things that die on the boundary between nodeBefore and nodeAfter. It is
     72// conservative in the sense that it might resort to telling you some things that are still live at
     73// nodeAfter.
     74template<typename Functor>
     75void forAllKilledOperands(Graph& graph, Node* nodeBefore, Node* nodeAfter, const Functor& functor)
     76{
     77    CodeOrigin before = nodeBefore->origin.forExit;
    7778    CodeOrigin after = nodeAfter->origin.forExit;
     79   
     80    VirtualRegister alreadyNoted;
     81    if (!!after) {
     82        // If we MovHint something that is live at the time, then we kill the old value.
     83        if (nodeAfter->containsMovHint()) {
     84            VirtualRegister reg = nodeAfter->unlinkedLocal();
     85            if (graph.isLiveInBytecode(reg, after)) {
     86                functor(reg);
     87                alreadyNoted = reg;
     88            }
     89        }
     90    }
    7891   
    7992    if (!before) {
     
    8396        // many such predecessors and they will likely all have a different origin. So, it's better
    8497        // to do the conservative thing.
    85         for (unsigned i = graph.block(0)->variablesAtHead.numberOfLocals(); i--;) {
    86             VirtualRegister reg = virtualRegisterForLocal(i);
    87             if (graph.isLiveInBytecode(reg, after))
    88                 functor(reg);
    89         }
     98        graph.forAllLocalsLiveInBytecode(after, functor);
    9099        return;
    91     }
    92    
    93     // If we MovHint something that is live at the time, then we kill the old value.
    94     VirtualRegister alreadyNoted;
    95     if (nodeAfter->containsMovHint()) {
    96         VirtualRegister reg = nodeAfter->unlinkedLocal();
    97         if (graph.isLiveInBytecode(reg, after)) {
    98             functor(reg);
    99             alreadyNoted = reg;
    100         }
    101100    }
    102101   
     
    107106    ASSERT(!!after);
    108107   
     108    // It's easier to do this if the inline call frames are the same. This is way faster than the
     109    // other loop, below.
     110    if (before.inlineCallFrame == after.inlineCallFrame) {
     111        int stackOffset = before.inlineCallFrame ? before.inlineCallFrame->stackOffset : 0;
     112        CodeBlock* codeBlock = graph.baselineCodeBlockFor(before.inlineCallFrame);
     113        FullBytecodeLiveness& fullLiveness = graph.livenessFor(codeBlock);
     114        const FastBitVector& liveBefore = fullLiveness.getLiveness(before.bytecodeIndex);
     115        const FastBitVector& liveAfter = fullLiveness.getLiveness(after.bytecodeIndex);
     116       
     117        for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
     118            if (liveBefore.get(relativeLocal) && !liveAfter.get(relativeLocal))
     119                functor(virtualRegisterForLocal(relativeLocal) + stackOffset);
     120        }
     121       
     122        return;
     123    }
     124   
    109125    // Detect kills the super conservative way: it is killed if it was live before and dead after.
    110     for (unsigned i = graph.block(0)->variablesAtHead.numberOfLocals(); i--;) {
    111         VirtualRegister reg = virtualRegisterForLocal(i);
    112         if (reg == alreadyNoted)
    113             continue;
    114         if (graph.isLiveInBytecode(reg, before) && !graph.isLiveInBytecode(reg, after))
     126    BitVector liveAfter = graph.localsLiveInBytecode(after);
     127    graph.forAllLocalsLiveInBytecode(
     128        before,
     129        [&] (VirtualRegister reg) {
     130            if (reg == alreadyNoted)
     131                return;
     132            if (liveAfter.get(reg.toLocal()))
     133                return;
    115134            functor(reg);
    116     }
     135        });
    117136}
    118137   
     
    141160        });
    142161
    143     CodeOrigin before;
     162    Node* before = nullptr;
    144163    if (nodeIndex)
    145         before = block->at(nodeIndex - 1)->origin.forExit;
     164        before = block->at(nodeIndex - 1);
    146165
    147166    forAllKilledOperands(
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r183162 r183207  
    945945        // Arguments are always live. This would be redundant if it wasn't for our
    946946        // op_call_varargs inlining.
    947         // FIXME: 'this' might not be live, but we don't have a way of knowing.
    948         // https://bugs.webkit.org/show_bug.cgi?id=128519
    949947        if (reg.isArgument()
    950948            && static_cast<size_t>(reg.toArgument()) < inlineCallFrame->arguments.size())
     
    955953   
    956954    return true;
     955}
     956
     957BitVector Graph::localsLiveInBytecode(CodeOrigin codeOrigin)
     958{
     959    BitVector result;
     960    result.ensureSize(block(0)->variablesAtHead.numberOfLocals());
     961    forAllLocalsLiveInBytecode(
     962        codeOrigin,
     963        [&] (VirtualRegister reg) {
     964            ASSERT(reg.isLocal());
     965            result.quickSet(reg.toLocal());
     966        });
     967    return result;
    957968}
    958969
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r183163 r183207  
    3030
    3131#include "AssemblyHelpers.h"
     32#include "BytecodeLivenessAnalysisInlines.h"
    3233#include "CodeBlock.h"
    3334#include "DFGArgumentPosition.h"
     
    4243#include "DFGPrePostNumbering.h"
    4344#include "DFGScannable.h"
     45#include "FullBytecodeLiveness.h"
    4446#include "JSStack.h"
    4547#include "MethodOfGettingAValueProfile.h"
     
    678680    FullBytecodeLiveness& livenessFor(CodeBlock*);
    679681    FullBytecodeLiveness& livenessFor(InlineCallFrame*);
     682   
     683    // Quickly query if a single local is live at the given point. This is faster than calling
     684    // forAllLiveInBytecode() if you will only query one local. But, if you want to know all of the
     685    // locals live, then calling this for each local is much slower than forAllLiveInBytecode().
    680686    bool isLiveInBytecode(VirtualRegister, CodeOrigin);
     687   
     688    // Quickly get all of the non-argument locals live at the given point. This doesn't give you
     689    // any arguments because those are all presumed live. You can call forAllLiveInBytecode() to
     690    // also get the arguments. This is much faster than calling isLiveInBytecode() for each local.
     691    template<typename Functor>
     692    void forAllLocalsLiveInBytecode(CodeOrigin codeOrigin, const Functor& functor)
     693    {
     694        // Support for not redundantly reporting arguments. Necessary because in case of a varargs
     695        // call, only the callee knows that arguments are live while in the case of a non-varargs
     696        // call, both callee and caller will see the variables live.
     697        VirtualRegister exclusionStart;
     698        VirtualRegister exclusionEnd;
     699       
     700        for (;;) {
     701            InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
     702            VirtualRegister stackOffset(inlineCallFrame ? inlineCallFrame->stackOffset : 0);
     703           
     704            if (inlineCallFrame) {
     705                if (inlineCallFrame->isClosureCall)
     706                    functor(stackOffset + JSStack::Callee);
     707                if (inlineCallFrame->isVarargs())
     708                    functor(stackOffset + JSStack::ArgumentCount);
     709            }
     710           
     711            CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame);
     712            FullBytecodeLiveness& fullLiveness = livenessFor(codeBlock);
     713            const FastBitVector& liveness = fullLiveness.getLiveness(codeOrigin.bytecodeIndex);
     714            for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
     715                VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal);
     716               
     717                // Don't report if our callee already reported.
     718                if (reg >= exclusionStart && reg < exclusionEnd)
     719                    continue;
     720               
     721                if (liveness.get(relativeLocal))
     722                    functor(reg);
     723            }
     724           
     725            if (!inlineCallFrame)
     726                break;
     727
     728            // Arguments are always live. This would be redundant if it wasn't for our
     729            // op_call_varargs inlining. See the comment above.
     730            exclusionStart = stackOffset + CallFrame::argumentOffsetIncludingThis(0);
     731            exclusionEnd = stackOffset + CallFrame::argumentOffsetIncludingThis(inlineCallFrame->arguments.size());
     732           
     733            // We will always have a "this" argument and exclusionStart should be a smaller stack
     734            // offset than exclusionEnd.
     735            ASSERT(exclusionStart < exclusionEnd);
     736
     737            for (VirtualRegister reg = exclusionStart; reg < exclusionEnd; reg += 1)
     738                functor(reg);
     739           
     740            codeOrigin = inlineCallFrame->caller;
     741        }
     742    }
     743   
     744    // Get a BitVector of all of the non-argument locals live right now. This is mostly useful if
     745    // you want to compare two sets of live locals from two different CodeOrigins.
     746    BitVector localsLiveInBytecode(CodeOrigin);
     747   
     748    // Tells you all of the arguments and locals live at the given CodeOrigin. This is a small
     749    // extension to forAllLocalsLiveInBytecode(), since all arguments are always presumed live.
     750    template<typename Functor>
     751    void forAllLiveInBytecode(CodeOrigin codeOrigin, const Functor& functor)
     752    {
     753        forAllLocalsLiveInBytecode(codeOrigin, functor);
     754       
     755        // Report all arguments as being live.
     756        for (unsigned argument = block(0)->variablesAtHead.numberOfArguments(); argument--;)
     757            functor(virtualRegisterForArgument(argument));
     758    }
    681759   
    682760    BytecodeKills& killsFor(CodeBlock*);
  • trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp

    r183201 r183207  
    8989    case PhantomLocal:
    9090    case CountExecution:
     91    case Jump:
     92    case Branch:
     93    case Unreachable:
    9194        break;
    9295       
  • trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp

    r183094 r183207  
    8181        Epoch currentEpoch = Epoch::first();
    8282       
    83         for (unsigned i = m_state.size(); i--;) {
    84             VirtualRegister reg = m_state.virtualRegisterForIndex(i);
    85             if (m_graph.isLiveInBytecode(reg, block->terminal()->origin.forExit))
    86                 m_state[i] = currentEpoch;
    87             else
    88                 m_state[i] = Epoch();
    89         }
     83        m_state.fill(Epoch());
     84        m_graph.forAllLiveInBytecode(
     85            block->terminal()->origin.forExit,
     86            [&] (VirtualRegister reg) {
     87                m_state.operand(reg) = currentEpoch;
     88            });
    9089       
    9190        if (verbose)
     
    115114            if (nodeIndex) {
    116115                forAllKilledOperands(
    117                     m_graph, block->at(nodeIndex - 1)->origin.forExit, node,
     116                    m_graph, block->at(nodeIndex - 1), node,
    118117                    [&] (VirtualRegister reg) {
    119118                        // This function is a bit sloppy - it might claim to kill a local even if
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r183201 r183207  
    5656    /* Any two nodes that are part of the same Phi graph will share the same */\
    5757    /* VariableAccessData, and thus will share predictions. FIXME: We should come up with */\
    58     /* better names for a lot of these. https://bugs.webkit.org/show_bug.cgi?id=137307 */\
    59     macro(GetLocal, NodeResultJS) \
     58    /* better names for a lot of these. https://bugs.webkit.org/show_bug.cgi?id=137307. */\
     59    /* Note that GetLocal is MustGenerate because it's our only way of knowing that some other */\
     60    /* basic block might have read a local variable in bytecode. We only remove GetLocals if it */\
     61    /* is redundant because of an earlier GetLocal or SetLocal in the same block. We could make */\
     62    /* these not MustGenerate and use a more sophisticated analysis to insert PhantomLocals in */\
     63    /* the same way that we insert Phantoms. https://bugs.webkit.org/show_bug.cgi?id=144086 */\
     64    macro(GetLocal, NodeResultJS | NodeMustGenerate) \
    6065    macro(SetLocal, 0) \
    6166    \
  • trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp

    r183072 r183207  
    5353#include "DFGObjectAllocationSinkingPhase.h"
    5454#include "DFGPhantomCanonicalizationPhase.h"
     55#include "DFGPhantomInsertionPhase.h"
    5556#include "DFGPhantomRemovalPhase.h"
    5657#include "DFGPredictionInjectionPhase.h"
     
    321322        performCPSRethreading(dfg);
    322323        performDCE(dfg);
     324        performPhantomInsertion(dfg);
    323325        performStackLayout(dfg);
    324326        performVirtualRegisterAllocation(dfg);
  • trunk/Source/JavaScriptCore/dfg/DFGScoreBoard.h

    r159886 r183207  
    5656    }
    5757   
     58    void sortFree()
     59    {
     60        std::sort(m_free.begin(), m_free.end());
     61    }
     62   
    5863    void assertClear()
    5964    {
    60 #if !ASSERT_DISABLED
     65        if (ASSERT_DISABLED)
     66            return;
     67       
    6168        // For every entry in the used list the use count of the virtual register should be zero, or max, due to it being a preserved local.
    6269        for (size_t i = 0; i < m_used.size(); ++i)
    63             ASSERT(!m_used[i] || m_used[i] == max());
     70            RELEASE_ASSERT(!m_used[i] || m_used[i] == max());
    6471        // For every entry in the free list, the use count should be zero.
    6572        for (size_t i = 0; i < m_free.size(); ++i)
    66             ASSERT(!m_used[m_free[i]]);
     73            RELEASE_ASSERT(!m_used[m_free[i]]);
    6774        // There must not be duplicates in the free list.
    6875        for (size_t i = 0; i < m_free.size(); ++i) {
    6976            for (size_t j = i + 1; j < m_free.size(); ++j)
    70                 ASSERT(m_free[i] != m_free[j]);
     77                RELEASE_ASSERT(m_free[i] != m_free[j]);
    7178        }
    72 #endif
    7379    }
    7480
  • trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp

    r180691 r183207  
    5656            if (!block->isReachable)
    5757                continue;
     58            if (!ASSERT_DISABLED) {
     59                // Force usage of highest-numbered virtual registers.
     60                scoreBoard.sortFree();
     61            }
    5862            for (size_t indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
    5963                Node* node = block->at(indexInBlock);
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r183201 r183207  
    72007200       
    72017201        AvailabilityMap availabilityMap = this->availabilityMap();
    7202        
    7203         for (unsigned i = 0; i < exit.m_values.size(); ++i) {
    7204             int operand = exit.m_values.operandForIndex(i);
    7205             bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin);
    7206             if (!isLive)
    7207                 availabilityMap.m_locals[i] = Availability();
    7208         }
     7202        availabilityMap.m_locals.fill(Availability());
     7203       
     7204        m_graph.forAllLiveInBytecode(
     7205            codeOrigin,
     7206            [&] (VirtualRegister reg) {
     7207                availabilityMap.m_locals.operand(reg) =
     7208                    this->availabilityMap().m_locals.operand(reg);
     7209            });
    72097210       
    72107211        availabilityMap.prune();
Note: See TracChangeset for help on using the changeset viewer.