Ignore:
Timestamp:
Sep 17, 2019, 12:52:43 PM (6 years ago)
Author:
[email protected]
Message:

[JSC] CheckArray+NonArray is not filtering out Array in AI
https://bugs.webkit.org/show_bug.cgi?id=201857
<rdar://problem/54194820>

Reviewed by Keith Miller.

JSTests:

  • stress/check-array-with-non-array-does-not-filter-arrays.js: Added.

(foo):

Source/JavaScriptCore:

The code of DFG::ArrayMode::alreadyChecked is different from SpeculativeJIT's CheckArray / CheckStructure.
While we assume CheckArray+NonArray ensures it only passes non-array inputs, DFG::ArrayMode::alreadyChecked
accepts arrays too. So CheckArray+NonArray is removed in AI if the input is proven that it is an array.
This patch aligns DFG::ArrayMode::alreadyChecked to the checks done at runtime.

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::ArrayMode::alreadyChecked const):

File:
1 edited

Legend:

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

    r249880 r249976  
    418418bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value, IndexingType shape) const
    419419{
     420    ASSERT(isSpecific());
     421
     422    IndexingType indexingModeMask = IsArray | IndexingShapeMask;
     423    if (action() == Array::Write)
     424        indexingModeMask |= CopyOnWrite;
     425
    420426    switch (arrayClass()) {
    421     case Array::OriginalArray: {
    422         if (value.m_structure.isTop())
     427    case Array::Array: {
     428        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape | IsArray)))
     429            return true;
     430        if (!value.m_structure.isFinite())
    423431            return false;
    424432        for (unsigned i = value.m_structure.size(); i--;) {
    425433            RegisteredStructure structure = value.m_structure[i];
    426             if ((structure->indexingType() & IndexingShapeMask) != shape)
     434            if ((structure->indexingMode() & indexingModeMask) != (shape | IsArray))
    427435                return false;
    428             if (isCopyOnWrite(structure->indexingMode()) && action() == Array::Write)
    429                 return false;
    430             if (!(structure->indexingType() & IsArray))
    431                 return false;
    432             if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure.get()))
    433                 return false;
    434436        }
    435437        return true;
    436438    }
    437        
    438     case Array::Array: {
    439         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape | IsArray)))
     439
     440    // Array::OriginalNonArray can be shown when the value is a TypedArray with original structure.
     441    // But here, we already filtered TypedArrays. So, just handle it like a NonArray.
     442    case Array::OriginalNonArray:
     443    case Array::NonArray: {
     444        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape)))
    440445            return true;
    441         if (value.m_structure.isTop())
     446        if (!value.m_structure.isFinite())
    442447            return false;
    443448        for (unsigned i = value.m_structure.size(); i--;) {
    444449            RegisteredStructure structure = value.m_structure[i];
    445             if ((structure->indexingMode() & IndexingShapeMask) != shape)
     450            if ((structure->indexingMode() & indexingModeMask) != shape)
    446451                return false;
    447             if (isCopyOnWrite(structure->indexingMode()) && action() == Array::Write)
    448                 return false;
    449             if (!(structure->indexingType() & IsArray))
    450                 return false;
    451452        }
    452453        return true;
    453454    }
    454        
    455     default: {
     455
     456    case Array::PossiblyArray: {
    456457        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape) | asArrayModesIgnoringTypedArrays(shape | IsArray)))
    457458            return true;
    458         if (value.m_structure.isTop())
     459        if (!value.m_structure.isFinite())
    459460            return false;
    460461        for (unsigned i = value.m_structure.size(); i--;) {
    461462            RegisteredStructure structure = value.m_structure[i];
    462             if ((structure->indexingMode() & IndexingShapeMask) != shape)
     463            if ((structure->indexingMode() & (indexingModeMask & ~IsArray)) != shape)
    463464                return false;
    464             if (isCopyOnWrite(structure->indexingMode()) && action() == Array::Write)
    465                 return false;
    466465        }
    467466        return true;
    468     } }
     467    }
     468
     469    // If ArrayMode is Array::OriginalCopyOnWriteArray or Array::OriginalArray, CheckArray is never emitted. Instead, we always emit CheckStructure.
     470    // So, we should perform the same check to the CheckStructure here.
     471    case Array::OriginalArray:
     472    case Array::OriginalCopyOnWriteArray: {
     473        if (!value.m_structure.isFinite())
     474            return false;
     475        Structure* originalStructure = originalArrayStructure(graph, node);
     476        if (value.m_structure.size() != 1)
     477            return false;
     478        return value.m_structure.onlyStructure().get() == originalStructure;
     479    }
     480    }
    469481}
    470482
Note: See TracChangeset for help on using the changeset viewer.