Changeset 50704 in webkit


Ignore:
Timestamp:
Nov 9, 2009 6:19:04 PM (14 years ago)
Author:
oliver@apple.com
Message:

Can cache prototype lookups on uncacheable dictionaries.
https://bugs.webkit.org/show_bug.cgi?id=31198

Reviewed by Gavin Barraclough.

Replace fromDictionaryTransition with flattenDictionaryObject and
flattenDictionaryStructure. This change is necessary as we need to
guarantee that our attempt to convert away from a dictionary structure
will definitely succeed, and in some cases this requires mutating the
object storage itself.

Location:
trunk
Files:
3 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r50703 r50704  
     12009-11-09  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Gavin Barraclough.
     4
     5        Can cache prototype lookups on uncacheable dictionaries.
     6        https://bugs.webkit.org/show_bug.cgi?id=31198
     7
     8        Replace fromDictionaryTransition with flattenDictionaryObject and
     9        flattenDictionaryStructure.  This change is necessary as we need to
     10        guarantee that our attempt to convert away from a dictionary structure
     11        will definitely succeed, and in some cases this requires mutating the
     12        object storage itself.
     13
     14        * interpreter/Interpreter.cpp:
     15        (JSC::Interpreter::tryCacheGetByID):
     16        * jit/JITStubs.cpp:
     17        (JSC::JITThunks::tryCacheGetByID):
     18        (JSC::DEFINE_STUB_FUNCTION):
     19        * runtime/BatchedTransitionOptimizer.h:
     20        (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer):
     21        * runtime/JSObject.h:
     22        (JSC::JSObject::flattenDictionaryObject):
     23        * runtime/Operations.h:
     24        (JSC::normalizePrototypeChain):
     25        * runtime/Structure.cpp:
     26        (JSC::Structure::flattenDictionaryStructure):
     27        (JSC::comparePropertyMapEntryIndices):
     28        * runtime/Structure.h:
     29
    1302009-11-09  Laszlo Gombos  <laszlo.1.gombos@nokia.com>
    231
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r50675 r50704  
    10431043        // should not be treated as a dictionary.
    10441044        if (baseObject->structure()->isDictionary())
    1045             baseObject->setStructure(Structure::fromDictionaryTransition(baseObject->structure()));
     1045            baseObject->flattenDictionaryObject();
    10461046
    10471047        ASSERT(!baseObject->structure()->isUncacheableDictionary());
  • trunk/JavaScriptCore/jit/JITStubs.cpp

    r50443 r50704  
    772772        // should not be treated as a dictionary.
    773773        if (slotBaseObject->structure()->isDictionary())
    774             slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
     774            slotBaseObject->flattenDictionaryObject();
    775775       
    776776        stubInfo->initGetByIdProto(structure, slotBaseObject->structure());
     
    11821182        // should not be treated as a dictionary.
    11831183        if (slotBaseObject->structure()->isDictionary())
    1184             slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
     1184            slotBaseObject->flattenDictionaryObject();
    11851185
    11861186        // The result fetched should always be the callee!
     
    13351335        // should not be treated as a dictionary.
    13361336        if (slotBaseObject->structure()->isDictionary())
    1337             slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
     1337            slotBaseObject->flattenDictionaryObject();
    13381338
    13391339        int listIndex;
  • trunk/JavaScriptCore/runtime/BatchedTransitionOptimizer.h

    r48582 r50704  
    4444        ~BatchedTransitionOptimizer()
    4545        {
    46             m_object->setStructure(Structure::fromDictionaryTransition(m_object->structure()));
     46            m_object->flattenDictionaryObject();
    4747        }
    4848
  • trunk/JavaScriptCore/runtime/JSObject.h

    r50254 r50704  
    211211        }
    212212
     213        void flattenDictionaryObject()
     214        {
     215            m_structure->flattenDictionaryStructure(this);
     216        }
     217
    213218    protected:
    214219        static const unsigned StructureFlags = 0;
  • trunk/JavaScriptCore/runtime/Operations.h

    r49734 r50704  
    244244            // should not be treated as a dictionary.
    245245            if (cell->structure()->isDictionary())
    246                 asObject(cell)->setStructure(Structure::fromDictionaryTransition(cell->structure()));
     246                asObject(cell)->flattenDictionaryObject();
    247247
    248248            ++count;
     
    266266            // should not be treated as a dictionary.
    267267            if (base->structure()->isDictionary())
    268                 asObject(base)->setStructure(Structure::fromDictionaryTransition(base->structure()));
     268                asObject(base)->flattenDictionaryObject();
    269269
    270270            ++count;
  • trunk/JavaScriptCore/runtime/Structure.cpp

    r50320 r50704  
    7878#endif
    7979
     80static int comparePropertyMapEntryIndices(const void* a, const void* b);
     81
    8082void Structure::dumpStatistics()
    8183{
     
    535537}
    536538
    537 PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure)
    538 {
    539     ASSERT(structure->isDictionary());
    540 
    541     // Since dictionary Structures are not shared, and no opcodes specialize
    542     // for them, we don't need to allocate a new Structure when transitioning
    543     // to non-dictionary status.
    544 
    545     // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the
    546     // deleted offsets vector) before transitioning from dictionary.
    547     if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty())
    548         structure->m_dictionaryKind = NoneDictionaryKind;
    549 
    550     return structure;
     539PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object)
     540{
     541    ASSERT(isDictionary());
     542    if (isUncacheableDictionary()) {
     543        ASSERT(m_propertyTable);
     544        Vector<PropertyMapEntry*> sortedPropertyEntries(m_propertyTable->keyCount);
     545        PropertyMapEntry** p = sortedPropertyEntries.data();
     546        unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
     547        for (unsigned i = 1; i <= entryCount; i++) {
     548            if (m_propertyTable->entries()[i].key)
     549                *p++ = &m_propertyTable->entries()[i];
     550        }
     551        size_t propertyCount = p - sortedPropertyEntries.data();
     552        qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);
     553        sortedPropertyEntries.resize(propertyCount);
     554
     555        // We now have the properties currently defined on this object
     556        // in the order that they are expected to be in, but we need to
     557        // reorder the storage, so we have to copy the current values out
     558        Vector<JSValue> values(propertyCount);
     559        unsigned anonymousSlotCount = m_propertyTable->anonymousSlotCount;
     560        for (unsigned i = 0; i < propertyCount; i++) {
     561            PropertyMapEntry* entry = sortedPropertyEntries[i];
     562            values[i] = object->getDirectOffset(entry->offset);
     563            // Update property table to have the new property offsets
     564            entry->offset = anonymousSlotCount + i;
     565            entry->index = i;
     566        }
     567       
     568        // Copy the original property values into their final locations
     569        for (unsigned i = 0; i < propertyCount; i++)
     570            object->putDirectOffset(anonymousSlotCount + i, values[i]);
     571
     572        if (m_propertyTable->deletedOffsets) {
     573            delete m_propertyTable->deletedOffsets;
     574            m_propertyTable->deletedOffsets = 0;
     575        }
     576    }
     577
     578    m_dictionaryKind = NoneDictionaryKind;
     579    return this;
    551580}
    552581
     
    10051034}
    10061035
    1007 static int comparePropertyMapEntryIndices(const void* a, const void* b)
     1036int comparePropertyMapEntryIndices(const void* a, const void* b)
    10081037{
    10091038    unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;
  • trunk/JavaScriptCore/runtime/Structure.h

    r50254 r50704  
    7575        static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
    7676        static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
    77         static PassRefPtr<Structure> fromDictionaryTransition(Structure*);
     77
     78        PassRefPtr<Structure> flattenDictionaryStructure(JSObject*);
    7879
    7980        ~Structure();
  • trunk/LayoutTests/ChangeLog

    r50698 r50704  
     12009-11-09  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Gavin Barraclough.
     4
     5        Can cache prototype lookups on uncacheable dictionaries.
     6        https://bugs.webkit.org/show_bug.cgi?id=31198
     7
     8        Add tests for lookup on uncacheable prototype.
     9
     10        * fast/js/dictionary-prototype-caching-expected.txt: Added.
     11        * fast/js/dictionary-prototype-caching.html: Added.
     12        * fast/js/script-tests/dictionary-prototype-caching.js: Added.
     13        (protoTest):
     14
    1152009-11-09  Anders Carlsson  <andersca@apple.com>
    216
Note: See TracChangeset for help on using the changeset viewer.