Ignore:
Timestamp:
Aug 20, 2013, 3:17:29 PM (12 years ago)
Author:
[email protected]
Message:

<https://webkit.org/b/120079> Flattening a dictionary can cause CopiedSpace corruption

Reviewed by Oliver Hunt.

When we flatten an object in dictionary mode, we compact its properties. If the object
had out-of-line storage in the form of a Butterfly prior to this compaction, and after
compaction its properties fit inline, the object's Structure "forgets" that the object
has a non-zero Butterfly pointer. During GC, we check the Butterfly and reportLiveBytes
with bytes = 0, which causes all sorts of badness in CopiedSpace.

Instead, after we flatten a dictionary, if properties fit inline we should clear the
Butterfly pointer so that the GC doesn't get confused later.

This patch does this clearing, and it also adds JSObject::checkStructure, which overrides
JSCell::checkStructure to add an ASSERT that makes sure that the Structure being assigned
agrees with the whether or not the object has a Butterfly. Also added an ASSERT to check
that the number of bytes reported to SlotVisitor::copyLater is non-zero.

  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::copyLater):

  • runtime/JSObject.cpp:

(JSC::JSObject::notifyPresenceOfIndexedAccessors):
(JSC::JSObject::convertUndecidedToInt32):
(JSC::JSObject::convertUndecidedToDouble):
(JSC::JSObject::convertUndecidedToContiguous):
(JSC::JSObject::convertInt32ToDouble):
(JSC::JSObject::convertInt32ToContiguous):
(JSC::JSObject::genericConvertDoubleToContiguous):
(JSC::JSObject::switchToSlowPutArrayStorage):
(JSC::JSObject::setPrototype):
(JSC::JSObject::putDirectAccessor):
(JSC::JSObject::seal):
(JSC::JSObject::freeze):
(JSC::JSObject::preventExtensions):
(JSC::JSObject::reifyStaticFunctionsForDelete):
(JSC::JSObject::removeDirect):

  • runtime/JSObject.h:

(JSC::JSObject::setButterfly):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::setStructure):
(JSC::JSObject::setStructureAndReallocateStorageIfNecessary):

  • runtime/Structure.cpp:

(JSC::Structure::flattenDictionaryStructure):

File:
1 edited

Legend:

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

    r154337 r154366  
    584584        return;
    585585   
    586     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors));
     586    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors), m_butterfly);
    587587   
    588588    if (!vm.prototypeMap.isPrototype(this))
     
    670670{
    671671    ASSERT(hasUndecided(structure()->indexingType()));
    672     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32));
     672    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32), m_butterfly);
    673673    return m_butterfly->contiguousInt32();
    674674}
     
    681681        m_butterfly->contiguousDouble()[i] = QNaN;
    682682   
    683     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
     683    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly);
    684684    return m_butterfly->contiguousDouble();
    685685}
     
    688688{
    689689    ASSERT(hasUndecided(structure()->indexingType()));
    690     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
     690    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
    691691    return m_butterfly->contiguous();
    692692}
     
    754754    }
    755755   
    756     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
     756    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly);
    757757    return m_butterfly->contiguousDouble();
    758758}
     
    762762    ASSERT(hasInt32(structure()->indexingType()));
    763763   
    764     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
     764    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
    765765    return m_butterfly->contiguous();
    766766}
     
    820820    }
    821821   
    822     setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
     822    setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
    823823    return m_butterfly->contiguous();
    824824}
     
    11181118    case ArrayWithArrayStorage: {
    11191119        Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
    1120         setStructure(vm, newStructure);
     1120        setStructure(vm, newStructure, m_butterfly);
    11211121        break;
    11221122    }
     
    11421142   
    11431143    Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
    1144     setStructure(vm, newStructure);
     1144    setStructure(vm, newStructure, m_butterfly);
    11451145   
    11461146    if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
     
    11991199    // if we override an existing non-getter or non-setter.
    12001200    if (slot.type() != PutPropertySlot::NewProperty)
    1201         setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes));
     1201        setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes), m_butterfly);
    12021202
    12031203    if (attributes & ReadOnly)
     
    15561556        return;
    15571557    preventExtensions(vm);
    1558     setStructure(vm, Structure::sealTransition(vm, structure()));
     1558    setStructure(vm, Structure::sealTransition(vm, structure()), m_butterfly);
    15591559}
    15601560
     
    15641564        return;
    15651565    preventExtensions(vm);
    1566     setStructure(vm, Structure::freezeTransition(vm, structure()));
     1566    setStructure(vm, Structure::freezeTransition(vm, structure()), m_butterfly);
    15671567}
    15681568
     
    15711571    enterDictionaryIndexingMode(vm);
    15721572    if (isExtensible())
    1573         setStructure(vm, Structure::preventExtensionsTransition(vm, structure()));
     1573        setStructure(vm, Structure::preventExtensionsTransition(vm, structure()), m_butterfly);
    15741574}
    15751575
     
    15891589
    15901590    if (!structure()->isUncacheableDictionary())
    1591         setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()));
     1591        setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()), m_butterfly);
    15921592
    15931593    for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
     
    16191619    }
    16201620
    1621     setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset));
     1621    setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset), m_butterfly);
    16221622    if (offset == invalidOffset)
    16231623        return false;
Note: See TracChangeset for help on using the changeset viewer.