Changeset 132701 in webkit


Ignore:
Timestamp:
Oct 26, 2012, 3:18:59 PM (13 years ago)
Author:
fpizlo@apple.com
Message:

Forward OSR calculation is wrong in the presence of multiple SetLocals, or a mix of SetLocals and Phantoms
https://bugs.webkit.org/show_bug.cgi?id=100461

Reviewed by Oliver Hunt and Gavin Barraclough.

This does a couple of things. First, it removes the part of the change in r131822 that made the forward
OSR exit calculator capable of handling multiple SetLocals. That change was wrong, because it would
blindly assume that all SetLocals had the same ValueRecovery, and would ignore the possibility that if
there is no value recovery then a ForwardCheckStructure on the first SetLocal would not know how to
recover the state associated with the second SetLocal. Then, it introduces the invariant that any bytecode
op that decomposes into multiple SetLocals must first emit dead SetLocals as hints and then emit a second
set of SetLocals to actually do the setting of the locals. This means that if a ForwardCheckStructure (or
any other hoisted forward speculation) is inserted, it will always be inserted on the second set of
SetLocals (since hoisting only touches the live ones), at which point OSR will already know about the
mov hints implied by the first set of (dead) SetLocals. This gives us the behavior we wanted, namely, that
a ForwardCheckStructure applied to a variant set by a resolve_with_base-like operation can correctly do a
forward exit while also ensuring that prior to exiting we set the appropriate locals.

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGOSRExit.cpp:

(JSC::DFG::OSRExit::OSRExit):

  • dfg/DFGOSRExit.h:

(OSRExit):

  • dfg/DFGOSRExitCompiler.cpp:
  • dfg/DFGOSRExitCompiler32_64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOSRExitCompiler64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward):

Location:
trunk/Source/JavaScriptCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r132636 r132701  
     12012-10-25  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Forward OSR calculation is wrong in the presence of multiple SetLocals, or a mix of SetLocals and Phantoms
     4        https://bugs.webkit.org/show_bug.cgi?id=100461
     5
     6        Reviewed by Oliver Hunt and Gavin Barraclough.
     7
     8        This does a couple of things. First, it removes the part of the change in r131822 that made the forward
     9        OSR exit calculator capable of handling multiple SetLocals. That change was wrong, because it would
     10        blindly assume that all SetLocals had the same ValueRecovery, and would ignore the possibility that if
     11        there is no value recovery then a ForwardCheckStructure on the first SetLocal would not know how to
     12        recover the state associated with the second SetLocal. Then, it introduces the invariant that any bytecode
     13        op that decomposes into multiple SetLocals must first emit dead SetLocals as hints and then emit a second
     14        set of SetLocals to actually do the setting of the locals. This means that if a ForwardCheckStructure (or
     15        any other hoisted forward speculation) is inserted, it will always be inserted on the second set of
     16        SetLocals (since hoisting only touches the live ones), at which point OSR will already know about the
     17        mov hints implied by the first set of (dead) SetLocals. This gives us the behavior we wanted, namely, that
     18        a ForwardCheckStructure applied to a variant set by a resolve_with_base-like operation can correctly do a
     19        forward exit while also ensuring that prior to exiting we set the appropriate locals.
     20
     21        * dfg/DFGByteCodeParser.cpp:
     22        (JSC::DFG::ByteCodeParser::parseBlock):
     23        * dfg/DFGOSRExit.cpp:
     24        (JSC::DFG::OSRExit::OSRExit):
     25        * dfg/DFGOSRExit.h:
     26        (OSRExit):
     27        * dfg/DFGOSRExitCompiler.cpp:
     28        * dfg/DFGOSRExitCompiler32_64.cpp:
     29        (JSC::DFG::OSRExitCompiler::compileExit):
     30        * dfg/DFGOSRExitCompiler64.cpp:
     31        (JSC::DFG::OSRExitCompiler::compileExit):
     32        * dfg/DFGSpeculativeJIT.cpp:
     33        (JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward):
     34
    1352012-10-26  Simon Hausmann  <simon.hausmann@digia.com>
    236
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r132499 r132701  
    31093109            NodeIndex value = 0;
    31103110            if (parseResolveOperations(prediction, identifier, operations, putToBaseOperation, &base, &value)) {
     3111                // First create OSR hints only.
     3112                set(baseDst, base);
     3113                set(valueDst, value);
     3114               
     3115                // If we try to hoist structure checks into here, then we're guaranteed that they will occur
     3116                // *after* we have already set up the values for OSR.
     3117               
     3118                // Then do the real SetLocals.
    31113119                set(baseDst, base);
    31123120                set(valueDst, value);
     
    31293137            NodeIndex value = 0;
    31303138            if (parseResolveOperations(prediction, identifier, operations, 0, &base, &value)) {
     3139                // First create OSR hints only.
     3140                set(baseDst, base);
     3141                set(valueDst, value);
     3142               
     3143                // If we try to hoist structure checks into here, then we're guaranteed that they will occur
     3144                // *after* we have already set up the values for OSR.
     3145               
     3146                // Then do the real SetLocals.
    31313147                set(baseDst, base);
    31323148                set(valueDst, value);
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp

    r131822 r132701  
    4646    , m_count(0)
    4747    , m_streamIndex(streamIndex)
     48    , m_lastSetOperand(jit->m_lastSetOperand)
    4849{
    4950    ASSERT(m_codeOrigin.isSet());
    50     m_setOperands.append(jit->m_lastSetOperand);
    5151}
    5252
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h

    r131822 r132701  
    111111   
    112112    unsigned m_streamIndex;
    113     Vector<int, 1> m_setOperands;
     113    int m_lastSetOperand;
    114114   
    115     Vector<RefPtr<ValueRecoveryOverride>, 1> m_valueRecoveryOverrides;
     115    RefPtr<ValueRecoveryOverride> m_valueRecoveryOverride;
    116116
    117117private:
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp

    r131822 r132701  
    7171    codeBlock->variableEventStream().reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->minifiedDFG(), exit.m_streamIndex, operands);
    7272   
    73     // There may be overrides, for forward speculations.
    74     for (size_t i = 0; i < exit.m_valueRecoveryOverrides.size(); i++)
    75         operands.setOperand(exit.m_valueRecoveryOverrides[i]->operand, exit.m_valueRecoveryOverrides[i]->recovery);
    76 
     73    // There may be an override, for forward speculations.
     74    if (!!exit.m_valueRecoveryOverride) {
     75        operands.setOperand(
     76            exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery);
     77    }
    7778   
    7879    SpeculationRecovery* recovery = 0;
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp

    r131868 r132701  
    733733    // 15) Load the result of the last bytecode operation into regT0.
    734734   
    735     for (size_t i = 0; i < exit.m_setOperands.size(); i++) {
    736         m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_setOperands[i]), GPRInfo::cachedResultRegister);
    737         m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_setOperands[i]), GPRInfo::cachedResultRegister2);
     735    if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) {
     736        m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
     737        m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister2);
    738738    }
    739739   
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp

    r131874 r132701  
    682682    // 16) Load the result of the last bytecode operation into regT0.
    683683   
    684     for (size_t i = 0; i < exit.m_setOperands.size(); i++)
    685         m_jit.load64(AssemblyHelpers::addressFor((VirtualRegister)exit.m_setOperands[i]), GPRInfo::cachedResultRegister);
    686 
     684    if (exit.m_lastSetOperand != std::numeric_limits<int>::max())
     685        m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
     686   
    687687    // 17) Adjust the call frame pointer.
    688688   
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r132162 r132701  
    154154void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecovery)
    155155{
    156 #if !ASSERT_DISABLED
    157156    if (!valueRecovery) {
    158157        // Check that the preceding node was a SetLocal with the same code origin.
    159158        Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(m_indexInBlock - 1));
    160         ASSERT(setLocal->op() == SetLocal);
    161         ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
    162     }
    163 #endif
     159        ASSERT_UNUSED(setLocal, setLocal->op() == SetLocal);
     160        ASSERT_UNUSED(setLocal, setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
     161       
     162        // Find the next node.
     163        unsigned indexInBlock = m_indexInBlock + 1;
     164        Node* node = 0;
     165        for (;;) {
     166            if (indexInBlock == m_jit.graph().m_blocks[m_block]->size()) {
     167                // This is an inline return. Give up and do a backwards speculation. This is safe
     168                // because an inline return has its own bytecode index and it's always safe to
     169                // reexecute that bytecode.
     170                ASSERT(node->op() == Jump);
     171                return;
     172            }
     173            node = &at(m_jit.graph().m_blocks[m_block]->at(indexInBlock));
     174            if (node->codeOrigin != at(m_compileIndex).codeOrigin)
     175                break;
     176            indexInBlock++;
     177        }
     178       
     179        ASSERT(node->codeOrigin != at(m_compileIndex).codeOrigin);
     180        OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
     181        exit.m_codeOrigin = node->codeOrigin;
     182        return;
     183    }
    164184   
    165185    unsigned setLocalIndexInBlock = m_indexInBlock + 1;
    166 
    167     OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
    168 
     186   
    169187    Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock));
    170188    bool hadInt32ToDouble = false;
     
    176194    if (setLocal->op() == Flush || setLocal->op() == Phantom)
    177195        setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
    178    
    179     if (!!valueRecovery) {
    180         if (hadInt32ToDouble)
    181             ASSERT(at(setLocal->child1()).child1() == m_compileIndex);
    182         else
    183             ASSERT(setLocal->child1() == m_compileIndex);
    184     }
     196       
     197    if (hadInt32ToDouble)
     198        ASSERT(at(setLocal->child1()).child1() == m_compileIndex);
     199    else
     200        ASSERT(setLocal->child1() == m_compileIndex);
    185201    ASSERT(setLocal->op() == SetLocal);
    186202    ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
     
    191207        return;
    192208    }
    193 
    194     exit.m_setOperands[0] = setLocal->local();
    195     while (nextNode->codeOrigin == at(m_compileIndex).codeOrigin) {
    196         ++setLocalIndexInBlock;
    197         Node* nextSetLocal = nextNode;
    198         if (nextSetLocal->op() == Int32ToDouble)
    199             nextSetLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
    200 
    201         if (nextSetLocal->op() == Flush || nextSetLocal->op() == Phantom)
    202             nextSetLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
    203 
    204         nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1));
    205         ASSERT(nextNode->op() != Jump || nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
    206         ASSERT(nextSetLocal->op() == SetLocal);
    207         exit.m_setOperands.append(nextSetLocal->local());
    208     }
    209 
    210209    ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
    211 
     210       
     211    OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
    212212    exit.m_codeOrigin = nextNode->codeOrigin;
    213213       
    214     if (!valueRecovery)
    215         return;
    216 
    217     ASSERT(exit.m_setOperands.size() == 1);
    218     for (size_t i = 0; i < exit.m_setOperands.size(); i++)
    219         exit.m_valueRecoveryOverrides.append(adoptRef(new ValueRecoveryOverride(exit.m_setOperands[i], valueRecovery)));
    220 
     214    exit.m_lastSetOperand = setLocal->local();
     215    exit.m_valueRecoveryOverride = adoptRef(
     216        new ValueRecoveryOverride(setLocal->local(), valueRecovery));
    221217}
    222218
Note: See TracChangeset for help on using the changeset viewer.