Ignore:
Timestamp:
Sep 20, 2013, 5:24:08 PM (12 years ago)
Author:
[email protected]
Message:

(un)shiftCountWithAnyIndexingType will start over in the middle of copying if it sees a hole
https://bugs.webkit.org/show_bug.cgi?id=121717

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

This bug caused the array to become corrupted. We now check for holes before we start moving things,
and start moving things only once we've determined that there are none.

  • runtime/JSArray.cpp:

(JSC::JSArray::shiftCountWithAnyIndexingType):
(JSC::JSArray::unshiftCountWithAnyIndexingType):

LayoutTests:

Added test to make sure that splicing an array with holes works correctly.

  • js/array-splice-with-holes-expected.txt: Added.
  • js/array-splice-with-holes.html: Added.
  • js/script-tests/array-splice-with-holes.js: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSArray.cpp

    r155395 r156214  
    769769        if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
    770770            return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
    771        
     771
     772        // Storing to a hole is fine since we're still having a good time. But reading from a hole
     773        // is totally not fine, since we might have to read from the proto chain.
     774        // We have to check for holes before we start moving things around so that we don't get halfway
     775        // through shifting and then realize we should have been in ArrayStorage mode.
    772776        unsigned end = oldLength - count;
    773777        for (unsigned i = startIndex; i < end; ++i) {
    774             // Storing to a hole is fine since we're still having a good time. But reading
    775             // from a hole is totally not fine, since we might have to read from the proto
    776             // chain.
    777778            JSValue v = m_butterfly->contiguous()[i + count].get();
    778             if (UNLIKELY(!v)) {
    779                 // The purpose of this path is to ensure that we don't make the same
    780                 // mistake in the future: shiftCountWithArrayStorage() can't do anything
    781                 // about holes (at least for now), but it can detect them quickly. So
    782                 // we convert to array storage and then allow the array storage path to
    783                 // figure it out.
     779            if (UNLIKELY(!v))
    784780                return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
    785             }
     781        }
     782
     783        for (unsigned i = startIndex; i < end; ++i) {
     784            JSValue v = m_butterfly->contiguous()[i + count].get();
     785            ASSERT(v);
    786786            // No need for a barrier since we're just moving data around in the same vector.
    787787            // This is in line with our standing assumption that we won't have a deletion
     
    804804        if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
    805805            return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
    806        
     806
     807        // Storing to a hole is fine since we're still having a good time. But reading from a hole
     808        // is totally not fine, since we might have to read from the proto chain.
     809        // We have to check for holes before we start moving things around so that we don't get halfway
     810        // through shifting and then realize we should have been in ArrayStorage mode.
    807811        unsigned end = oldLength - count;
    808812        for (unsigned i = startIndex; i < end; ++i) {
    809             // Storing to a hole is fine since we're still having a good time. But reading
    810             // from a hole is totally not fine, since we might have to read from the proto
    811             // chain.
    812813            double v = m_butterfly->contiguousDouble()[i + count];
    813             if (UNLIKELY(v != v)) {
    814                 // The purpose of this path is to ensure that we don't make the same
    815                 // mistake in the future: shiftCountWithArrayStorage() can't do anything
    816                 // about holes (at least for now), but it can detect them quickly. So
    817                 // we convert to array storage and then allow the array storage path to
    818                 // figure it out.
     814            if (UNLIKELY(v != v))
    819815                return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
    820             }
     816        }
     817           
     818        for (unsigned i = startIndex; i < end; ++i) {
     819            double v = m_butterfly->contiguousDouble()[i + count];
     820            ASSERT(v == v);
    821821            // No need for a barrier since we're just moving data around in the same vector.
    822822            // This is in line with our standing assumption that we won't have a deletion
     
    903903       
    904904        ensureLength(exec->vm(), oldLength + count);
    905        
     905
     906        // We have to check for holes before we start moving things around so that we don't get halfway
     907        // through shifting and then realize we should have been in ArrayStorage mode.
    906908        for (unsigned i = oldLength; i-- > startIndex;) {
    907909            JSValue v = m_butterfly->contiguous()[i].get();
    908910            if (UNLIKELY(!v))
    909911                return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
     912        }
     913
     914        for (unsigned i = oldLength; i-- > startIndex;) {
     915            JSValue v = m_butterfly->contiguous()[i].get();
     916            ASSERT(v);
    910917            m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
    911918        }
     
    929936        ensureLength(exec->vm(), oldLength + count);
    930937       
     938        // We have to check for holes before we start moving things around so that we don't get halfway
     939        // through shifting and then realize we should have been in ArrayStorage mode.
    931940        for (unsigned i = oldLength; i-- > startIndex;) {
    932941            double v = m_butterfly->contiguousDouble()[i];
    933942            if (UNLIKELY(v != v))
    934943                return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
     944        }
     945
     946        for (unsigned i = oldLength; i-- > startIndex;) {
     947            double v = m_butterfly->contiguousDouble()[i];
     948            ASSERT(v == v);
    935949            m_butterfly->contiguousDouble()[i + count] = v;
    936950        }
Note: See TracChangeset for help on using the changeset viewer.