Ignore:
Timestamp:
Oct 16, 2009, 5:28:19 PM (16 years ago)
Author:
[email protected]
Message:

Fast for-in enumeration: Cache JSPropertyNameIterator; cache JSStrings
in JSPropertyNameIterator; inline more code.

Patch by Geoffrey Garen <[email protected]> on 2009-10-16
Reviewed by Oliver Hunt.

1.024x as fast on SunSpider (fasta: 1.43x as fast).

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dump):

  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitGetPropertyNames):
(JSC::BytecodeGenerator::emitNextPropertyName):

  • bytecompiler/BytecodeGenerator.h: Added a few extra operands to

op_get_pnames and op_next_pname so that we can track iteration state
in the register file instead of in the JSPropertyNameIterator. (To be
cacheable, the JSPropertyNameIterator must be stateless.)

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::tryCachePutByID):
(JSC::Interpreter::tryCacheGetByID): Updated for rename to
"normalizePrototypeChain" and removal of "isCacheable".

(JSC::Interpreter::privateExecute): Updated for in-RegisterFile
iteration state tracking.

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_get_pnames): Updated for in-RegisterFile
iteration state tracking.

(JSC::JIT::emit_op_next_pname): Inlined code generation for op_next_pname.

  • jit/JITStubs.cpp:

(JSC::JITThunks::tryCachePutByID):
(JSC::JITThunks::tryCacheGetByID): Updated for rename to
"normalizePrototypeChain" and removal of "isCacheable".

(JSC::DEFINE_STUB_FUNCTION):

  • jit/JITStubs.h:

(JSC::): Added has_property and to_object stubs. Removed op_next_pname
stub, since has_property is all we need anymore.

  • parser/Nodes.cpp:

(JSC::ForInNode::emitBytecode): Updated for in-RegisterFile
iteration state tracking.

  • runtime/JSCell.h:
  • runtime/JSObject.cpp:

(JSC::JSObject::getPropertyNames): Don't do caching at this layer
anymore, since we don't create a JSPropertyNameIterator at this layer.

  • runtime/JSPropertyNameIterator.cpp:

(JSC::JSPropertyNameIterator::create): Do do caching at this layer.
(JSC::JSPropertyNameIterator::get): Updated for in-RegisterFile
iteration state tracking.
(JSC::JSPropertyNameIterator::markChildren): Mark our JSStrings.

  • runtime/JSPropertyNameIterator.h:

(JSC::JSPropertyNameIterator::size):
(JSC::JSPropertyNameIterator::setCachedStructure):
(JSC::JSPropertyNameIterator::cachedStructure):
(JSC::JSPropertyNameIterator::setCachedPrototypeChain):
(JSC::JSPropertyNameIterator::cachedPrototypeChain):
(JSC::JSPropertyNameIterator::JSPropertyNameIterator):
(JSC::Structure::setEnumerationCache): Don't store iteration state in
a JSPropertyNameIterator. Do cache a JSPropertyNameIterator in a
Structure.

  • runtime/JSValue.h:

(JSC::asCell):

  • runtime/MarkStack.h: Make those mischievous #include gods happy.
  • runtime/ObjectConstructor.cpp:
  • runtime/Operations.h:

(JSC::normalizePrototypeChain): Renamed countPrototypeChainEntriesAndCheckForProxies
to normalizePrototypeChain, since it changes dictionary prototypes to
non-dictionary objects.

  • runtime/PropertyNameArray.cpp:

(JSC::PropertyNameArray::add):

  • runtime/PropertyNameArray.h:

(JSC::PropertyNameArrayData::PropertyNameArrayData):
(JSC::PropertyNameArray::data):
(JSC::PropertyNameArray::size):
(JSC::PropertyNameArray::begin):
(JSC::PropertyNameArray::end): Simplified some code here to help with
current and future refactoring.

  • runtime/Protect.h:
  • runtime/Structure.cpp:

(JSC::Structure::~Structure):
(JSC::Structure::addPropertyWithoutTransition):
(JSC::Structure::removePropertyWithoutTransition): No need to clear
the enumeration cache with adding / removing properties without
transition. It is an error to add / remove properties without transition
once an object has been observed, and we can ASSERT to catch that.

  • runtime/Structure.h:

(JSC::Structure::enumerationCache): Changed the enumeration cache to
hold a JSPropertyNameIterator.

  • runtime/StructureChain.cpp:
  • runtime/StructureChain.h:

(JSC::StructureChain::head): Removed StructureChain::isCacheable because
it was wrong-headed in two ways: (1) It gave up when a prototype was a
dictionary, but instead we want un-dictionary heavily accessed
prototypes; (2) It folded a test for hasDefaultGetPropertyNames() into
a generic test for "cacheable-ness", but hasDefaultGetPropertyNames()
is only releavant to for-in caching.

File:
1 edited

Legend:

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

    r49649 r49717  
    3232#include "JSObject.h"
    3333#include "JSString.h"
     34#include "Operations.h"
    3435#include "PropertyNameArray.h"
    3536
     
    4041
    4142    class JSPropertyNameIterator : public JSCell {
     43        friend class JIT;
     44
    4245    public:
    43         static JSPropertyNameIterator* create(ExecState*, JSValue);
    44 
    45         virtual ~JSPropertyNameIterator();
    46 
    47         virtual void markChildren(MarkStack&);
    48 
    49         JSValue next(ExecState*);
    50         void invalidate();
     46        static JSPropertyNameIterator* create(ExecState*, JSObject*);
    5147       
    5248        static PassRefPtr<Structure> createStructure(JSValue prototype)
     
    5450            return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren));
    5551        }
     52
     53        virtual void markChildren(MarkStack&);
     54
     55        JSValue get(ExecState*, JSObject*, size_t i);
     56        size_t size() { return m_jsStringsSize; }
     57
     58        void setCachedStructure(Structure* structure) { m_cachedStructure = structure; }
     59        Structure* cachedStructure() { return m_cachedStructure; }
     60
     61        void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
     62        StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
     63
    5664    private:
    57         JSPropertyNameIterator(ExecState*);
    58         JSPropertyNameIterator(ExecState*, JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData);
     65        JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData);
    5966
    60         JSObject* m_object;
    61         RefPtr<PropertyNameArrayData> m_data;
    62         PropertyNameArrayData::const_iterator m_position;
    63         PropertyNameArrayData::const_iterator m_end;
     67        Structure* m_cachedStructure;
     68        RefPtr<StructureChain> m_cachedPrototypeChain;
     69        size_t m_jsStringsSize;
     70        OwnArrayPtr<JSValue> m_jsStrings;
    6471    };
    6572
    66 inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec)
     73inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData)
    6774    : JSCell(exec->globalData().propertyNameIteratorStructure.get())
    68     , m_object(0)
    69     , m_position(0)
    70     , m_end(0)
     75    , m_cachedStructure(0)
     76    , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
     77    , m_jsStrings(new JSValue[m_jsStringsSize])
    7178{
     79    PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
     80    for (size_t i = 0; i < m_jsStringsSize; ++i)
     81        m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring());
    7282}
    7383
    74 inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, JSObject* object, PassRefPtr<PropertyNameArrayData> propertyNameArrayData)
    75     : JSCell(exec->globalData().propertyNameIteratorStructure.get())
    76     , m_object(object)
    77     , m_data(propertyNameArrayData)
    78     , m_position(m_data->begin())
    79     , m_end(m_data->end())
     84inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache)
    8085{
    81 }
    82 
    83 inline JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSValue v)
    84 {
    85     if (v.isUndefinedOrNull())
    86         return new (exec) JSPropertyNameIterator(exec);
    87 
    88     JSObject* o = v.toObject(exec);
    89     PropertyNameArray propertyNames(exec);
    90     o->getPropertyNames(exec, propertyNames);
    91     return new (exec) JSPropertyNameIterator(exec, o, propertyNames.releaseData());
    92 }
    93 
    94 inline JSValue JSPropertyNameIterator::next(ExecState* exec)
    95 {
    96     if (m_position == m_end)
    97         return JSValue();
    98 
    99     if (m_data->cachedStructure() == m_object->structure() && m_data->cachedPrototypeChain() == m_object->structure()->prototypeChain(exec))
    100         return jsOwnedString(exec, (*m_position++).ustring());
    101 
    102     do {
    103         if (m_object->hasProperty(exec, *m_position))
    104             return jsOwnedString(exec, (*m_position++).ustring());
    105         m_position++;
    106     } while (m_position != m_end);
    107 
    108     return JSValue();
     86    ASSERT(!isDictionary());
     87    m_enumerationCache = enumerationCache;
    10988}
    11089
Note: See TracChangeset for help on using the changeset viewer.