Ignore:
Timestamp:
Sep 15, 2012, 7:36:22 PM (13 years ago)
Author:
[email protected]
Message:

Structure check hoisting fails to consider the possibility of conflicting checks on the source of the first assignment to the hoisted variable
https://bugs.webkit.org/show_bug.cgi?id=96872

Reviewed by Oliver Hunt.

This does a few related things:

  • It turns off the use of ForceOSRExit for sure-to-fail CheckStructures, because I noticed that this would sometimes happen for a ForwardCheckStructure. The problem is that ForceOSRExit exits backwards, not forwards. Since the code that led to those ForceOSRExit's being inserted was written out of paranoia rather than need, I removed it. Specifically, I removed the m_isValid = false code for CheckStructure/StructureTransitionWatchpoint in AbstractState.


  • If a structure check causes a structure set to go empty, we don't want a PutStructure to revive the set. It should instead be smart enough to realize that an empty set implies that the code can't execute. This was the only "bug" that the use of m_isValid = false was preventing.


  • Finally, the main change: structure check hoisting looks at the source of the SetLocals on structure-check-hoistable variables and ensures that the source is not checked with a conflicting structure. This is O(n2) but it does not show up at all in performance tests.


The first two parts of this change were auxiliary bugs that were revealed by
the structure check hoister doing bad things.

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::execute):

  • dfg/DFGStructureCheckHoistingPhase.cpp:

(JSC::DFG::StructureCheckHoistingPhase::run):

File:
1 edited

Legend:

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

    r128544 r128699  
    148148            AbstractValue value;
    149149            value.setMostSpecific(graph.m_mustHandleValues[i]);
    150             block->valuesAtHead.operand(graph.m_mustHandleValues.operandForIndex(i)).merge(value);
     150            int operand = graph.m_mustHandleValues.operandForIndex(i);
     151            block->valuesAtHead.operand(operand).merge(value);
     152#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
     153            dataLog("    Initializing Block #%u, operand r%d, to ", blockIndex, operand);
     154            block->valuesAtHead.operand(operand).dump(WTF::dataFile());
     155            dataLog("\n");
     156#endif
    151157        }
    152158        block->cfaShouldRevisit = true;
     
    12941300            || !isCellSpeculation(value.m_type));
    12951301        value.filter(set);
    1296         // This is likely to be unnecessary, but it's conservative, and that's a good thing.
    1297         // This is trying to avoid situations where the CFA proves that this structure check
    1298         // must fail due to a future structure proof. We have two options at that point. We
    1299         // can either compile all subsequent code as we would otherwise, or we can ensure
    1300         // that the subsequent code is never reachable. The former is correct because the
    1301         // Proof Is Infallible (TM) -- hence even if we don't force the subsequent code to
    1302         // be unreachable, it must be unreachable nonetheless. But imagine what would happen
    1303         // if the proof was borked. In the former case, we'd get really bizarre bugs where
    1304         // we assumed that the structure of this object was known even though it wasn't. In
    1305         // the latter case, we'd have a slight performance pathology because this would be
    1306         // turned into an OSR exit unnecessarily. Which would you rather have?
    1307         if (value.m_currentKnownStructure.isClear()
    1308             || value.m_futurePossibleStructure.isClear())
    1309             m_isValid = false;
    13101302        m_haveStructures = true;
    13111303        break;
     
    13261318        ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
    13271319        value.filter(node.structure());
    1328         // See comment in CheckStructure for why this is here.
    1329         if (value.m_currentKnownStructure.isClear()
    1330             || value.m_futurePossibleStructure.isClear())
    1331             m_isValid = false;
    13321320        m_haveStructures = true;
    13331321        node.setCanExit(true);
     
    13381326    case PhantomPutStructure:
    13391327        node.setCanExit(false);
    1340         clobberStructures(indexInBlock);
    1341         forNode(node.child1()).set(node.structureTransitionData().newStructure);
    1342         m_haveStructures = true;
     1328        if (!forNode(node.child1()).m_currentKnownStructure.isClear()) {
     1329            clobberStructures(indexInBlock);
     1330            forNode(node.child1()).set(node.structureTransitionData().newStructure);
     1331            m_haveStructures = true;
     1332        }
    13431333        break;
    13441334    case GetButterfly:
Note: See TracChangeset for help on using the changeset viewer.