Changeset 47601 in webkit for trunk/JavaScriptCore/runtime


Ignore:
Timestamp:
Aug 20, 2009, 3:36:36 PM (16 years ago)
Author:
[email protected]
Message:

REGRESSION: significant slowdown on Celtic Kane "AJAX declaration" subtest
https://bugs.webkit.org/show_bug.cgi?id=28332

Reviewed by Gavin Barraclough.

The method check optimisation made transitions aware of the value being
assigned when a transition was assigning a function. This had the side
effect of making every assignment of a function expression result in a
new transition, and thus a new Structure. The net result of this is that
the common JS idiom of

function MyObject() {

this.myFunction = function(...){...};

}
new MyObject();

Will produce a unique structure on every iteration, meaning that all
caching is defeated and there is a significant amount of structure churn.

The fix is to return the transition to its original form where it is
keyed off a property name + attributes tuple, but have each transition
support an optional transition on a specific value.

Location:
trunk/JavaScriptCore/runtime
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/JSObject.h

    r47288 r47601  
    468468    }
    469469
     470    // If we have a specific function, we may have got to this point if there is
     471    // already a transition with the correct property name and attributes, but
     472    // specialized to a different function.  In this case we just want to give up
     473    // and despecialize the transition.
     474    // In this case we clear the value of specificFunction which will result
     475    // in us adding a non-specific transition, and any subsequent lookup in
     476    // Structure::addPropertyTransitionToExistingStructure will just use that.
     477    if (specificFunction && m_structure->hasTransition(propertyName, attributes))
     478        specificFunction = 0;
     479
    470480    RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
     481
    471482    if (currentCapacity != structure->propertyStorageCapacity())
    472483        allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
  • trunk/JavaScriptCore/runtime/Structure.cpp

    r47474 r47601  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    160160            m_previous->m_transitions.singleTransition = 0;
    161161        } else {
    162             ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious.get(), make_pair(m_attributesInPrevious, m_specificValueInPrevious))));
    163             m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious.get(), make_pair(m_attributesInPrevious, m_specificValueInPrevious)));
     162            ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious));
     163            m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
    164164        }
    165165    }
     
    393393        }
    394394    } else {
    395         if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), make_pair(attributes, specificValue)))) {
     395        if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes), specificValue)) {
    396396            ASSERT(existingTransition->m_offset != noOffset);
    397397            offset = existingTransition->m_offset;
     
    458458        StructureTransitionTable* transitionTable = new StructureTransitionTable;
    459459        structure->m_transitions.table = transitionTable;
    460         transitionTable->add(make_pair(existingTransition->m_nameInPrevious.get(), make_pair(existingTransition->m_attributesInPrevious, existingTransition->m_specificValueInPrevious)), existingTransition);
    461     }
    462     structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), make_pair(attributes, specificValue)), transition.get());
     460        transitionTable->add(make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
     461    }
     462    structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue);
    463463    return transition.release();
    464464}
     
    826826    checkConsistency();
    827827    return newOffset;
     828}
     829
     830bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
     831{
     832    if (m_usingSingleTransitionSlot) {
     833        return m_transitions.singleTransition &&
     834            m_transitions.singleTransition->m_nameInPrevious.get() == rep &&
     835            m_transitions.singleTransition->m_attributesInPrevious == attributes;
     836    }
     837    return m_transitions.table->hasTransition(make_pair(rep, attributes));
    828838}
    829839
  • trunk/JavaScriptCore/runtime/Structure.h

    r47022 r47601  
    106106            return get(propertyName._ustring.rep(), attributes, specificValue);
    107107        }
     108        bool transitionedFor(const JSCell* specificValue)
     109        {
     110            return m_specificValueInPrevious == specificValue;
     111        }
     112        bool hasTransition(UString::Rep* rep, unsigned attributes);
     113        bool hasTransition(const Identifier& propertyName, unsigned attributes)
     114        {
     115            return hasTransition(propertyName._ustring.rep(), attributes);
     116        }
    108117
    109118        void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
     
    167176        RefPtr<Structure> m_previous;
    168177        RefPtr<UString::Rep> m_nameInPrevious;
     178        JSCell* m_specificValueInPrevious;
    169179
    170180        union {
     
    172182            StructureTransitionTable* table;
    173183        } m_transitions;
    174         JSCell* m_specificValueInPrevious;
    175184
    176185        RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
     
    232241        }
    233242    }
    234 
     243   
     244    bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
     245    {
     246        const TransitionTable::iterator find = m_table.find(key);
     247        if (find == m_table.end()) {
     248            ASSERT(!m_table.contains(key));
     249            return false;
     250        }
     251        return find->second.first || find->second.second->transitionedFor(specificValue);
     252    }
     253
     254    Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
     255    {
     256        Transition transition = m_table.get(key);
     257        if (transition.second && transition.second->transitionedFor(specificValue))
     258            return transition.second;
     259        return transition.first;
     260    }
    235261} // namespace JSC
    236262
  • trunk/JavaScriptCore/runtime/StructureTransitionTable.h

    r44076 r47601  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838
    3939    struct StructureTransitionTableHash {
    40         typedef std::pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> > Key;
     40        typedef std::pair<RefPtr<UString::Rep>, unsigned> Key;
    4141        static unsigned hash(const Key& p)
    4242        {
     
    5454    struct StructureTransitionTableHashTraits {
    5555        typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits;
    56         typedef WTF::GenericHashTraits<unsigned> SecondFirstTraits;
    57         typedef WTF::GenericHashTraits<JSCell*> SecondSecondTraits;
    58         typedef std::pair<FirstTraits::TraitType, std::pair<SecondFirstTraits::TraitType, SecondSecondTraits::TraitType> > TraitType;
     56        typedef WTF::GenericHashTraits<unsigned> SecondTraits;
     57        typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
    5958
    60         static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondFirstTraits::emptyValueIsZero && SecondSecondTraits::emptyValueIsZero;
    61         static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), std::make_pair(SecondFirstTraits::emptyValue(), SecondSecondTraits::emptyValue())); }
     59        static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero;
     60        static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); }
    6261
    63         static const bool needsDestruction = FirstTraits::needsDestruction || SecondFirstTraits::needsDestruction || SecondSecondTraits::needsDestruction;
     62        static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction;
    6463
    6564        static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
     
    6766    };
    6867
    69     typedef HashMap<StructureTransitionTableHash::Key, Structure*, StructureTransitionTableHash, StructureTransitionTableHashTraits> StructureTransitionTable;
     68    class StructureTransitionTable {
     69        typedef std::pair<Structure*, Structure*> Transition;
     70        typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
     71    public:
     72        inline bool contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
     73        inline Structure* get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const;
     74        bool hasTransition(const StructureTransitionTableHash::Key& key)
     75        {
     76            return m_table.contains(key);
     77        }
     78        void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
     79        {
     80            TransitionTable::iterator find = m_table.find(key);
     81            if (!specificValue)
     82                find->second.first = 0;
     83            else
     84                find->second.second = 0;
     85            if (!find->second.first && !find->second.second)
     86                m_table.remove(find);
     87        }
     88        void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
     89        {
     90            if (!specificValue) {
     91                TransitionTable::iterator find = m_table.find(key);
     92                if (find == m_table.end())
     93                    m_table.add(key, Transition(structure, 0));
     94                else
     95                    find->second.first = structure;
     96            } else {
     97                // If we're adding a transition to a specific value, then there cannot be
     98                // an existing transition
     99                ASSERT(!m_table.contains(key));
     100                m_table.add(key, Transition(0, structure));
     101            }
     102               
     103
     104        }
     105    private:
     106        TransitionTable m_table;
     107    };
    70108
    71109} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.