Ignore:
Timestamp:
May 22, 2009, 6:48:32 PM (16 years ago)
Author:
[email protected]
Message:

2009-05-21 Gavin Barraclough <[email protected]>

Reviewed by Geoff Garen.

op_method_check

Optimize method calls, by caching specific function values within the Structure.
The new opcode is used almost like an x86 opcode prefix byte to optimize op_get_by_id,
where the property access is being used to read a function to be passed to op-call (i.e.
'foo.bar();'). This patch modifies the Structure class such that when a property is
put to an object for the first time we will check if the value is a function. If it is,
we will cache the function value on the Structure. A Structure in such a state guarantees
that not only does a property with the given identifier exist on the object, but also that
its value is unchanged. Upon any further attempt to put a property with the same identifier
(but a different value) to the object, it will transition back to a normal Structure (where
it will guarantee the presence but not the value of the property).

op_method_check makes use of the new information made available by the Structure, by
augmenting the functionality of op_get_by_id. Upon generating a FunctionCallDotNode a
check will be emitted prior to the property access reading the function value, and the JIT
will generate an extra (initially unlinked but patchable) set of checks prior to the regular
JIT code for get_by_id. The new code will do inline structure and prototype structure check
(unlike a regular get_by_id, which can only handle 'self' accesses inline), and then performs
an immediate load of the function value, rather than using memory accesses to load the value
from the obejct's property storage array. If the method check fails it will revert, or if
the access is polymorphic, the op_get_by_id will continue to operate - and optimize itself -
just as any other regular op_get_by_id would.

~2.5% on v8-tests, due to a ~9% progression on richards.

  • API/JSCallbackObjectFunctions.h: (JSC::::put): (JSC::::staticFunctionGetter):
  • API/JSObjectRef.cpp: (JSObjectMakeConstructor):
  • JavaScriptCore.exp:
  • assembler/AbstractMacroAssembler.h: (JSC::AbstractMacroAssembler::differenceBetween):
  • assembler/MacroAssemblerX86.h: (JSC::MacroAssemblerX86::moveWithPatch):
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump):
  • bytecode/CodeBlock.h: (JSC::getMethodCallLinkInfoReturnLocation): (JSC::CodeBlock::getMethodCallLinkInfo): (JSC::CodeBlock::addMethodCallLinkInfos): (JSC::CodeBlock::methodCallLinkInfo):
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitMethodCheck):
  • bytecompiler/BytecodeGenerator.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases): (JSC::JIT::privateCompile):
  • jit/JIT.h: (JSC::MethodCallCompilationInfo::MethodCallCompilationInfo):
  • jit/JITOpcodes.cpp:
  • jit/JITPropertyAccess.cpp: (JSC::JIT::emit_op_method_check): (JSC::JIT::emitSlow_op_method_check): (JSC::JIT::emit_op_get_by_id): (JSC::JIT::emitSlow_op_get_by_id): (JSC::JIT::emit_op_put_by_id): (JSC::JIT::emitSlow_op_put_by_id): (JSC::JIT::compileGetByIdHotPath): (JSC::JIT::compileGetByIdSlowCase): (JSC::JIT::patchMethodCallProto):
  • jit/JITStubs.cpp: (JSC::JITStubs::cti_op_get_by_id_method_check): (JSC::JITStubs::cti_op_get_by_id_method_check_second):
  • jit/JITStubs.h:
  • jsc.cpp: (GlobalObject::GlobalObject):
  • parser/Nodes.cpp: (JSC::FunctionCallDotNode::emitBytecode):
  • runtime/Arguments.cpp: (JSC::Arguments::put):
  • runtime/ArrayConstructor.cpp: (JSC::ArrayConstructor::ArrayConstructor):
  • runtime/BooleanConstructor.cpp: (JSC::BooleanConstructor::BooleanConstructor):
  • runtime/DateConstructor.cpp: (JSC::DateConstructor::DateConstructor):
  • runtime/ErrorConstructor.cpp: (JSC::ErrorConstructor::ErrorConstructor): (JSC::constructError):
  • runtime/ErrorPrototype.cpp: (JSC::ErrorPrototype::ErrorPrototype):
  • runtime/FunctionConstructor.cpp: (JSC::FunctionConstructor::FunctionConstructor):
  • runtime/FunctionPrototype.cpp: (JSC::FunctionPrototype::FunctionPrototype):
  • runtime/InternalFunction.cpp: (JSC::InternalFunction::InternalFunction):
  • runtime/JSActivation.cpp: (JSC::JSActivation::put): (JSC::JSActivation::putWithAttributes):
  • runtime/JSByteArray.cpp: (JSC::JSByteArray::JSByteArray):
  • runtime/JSFunction.cpp: (JSC::JSFunction::JSFunction): (JSC::JSFunction::getOwnPropertySlot):
  • runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::putWithAttributes): (JSC::JSGlobalObject::reset): (JSC::JSGlobalObject::mark):
  • runtime/JSGlobalObject.h: (JSC::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): (JSC::JSGlobalObject::methodCallDummy):
  • runtime/JSObject.cpp: (JSC::JSObject::put): (JSC::JSObject::putWithAttributes): (JSC::JSObject::deleteProperty): (JSC::JSObject::defineGetter): (JSC::JSObject::defineSetter): (JSC::JSObject::getPropertyAttributes): (JSC::JSObject::getPropertySpecificFunction): (JSC::JSObject::putDirectFunction): (JSC::JSObject::putDirectFunctionWithoutTransition):
  • runtime/JSObject.h: (JSC::getJSFunction): (JSC::JSObject::getDirectLocation): (JSC::JSObject::putDirect): (JSC::JSObject::putDirectWithoutTransition):
  • runtime/LiteralParser.cpp: (JSC::LiteralParser::parseObject):
  • runtime/Lookup.cpp: (JSC::setUpStaticFunctionSlot):
  • runtime/Lookup.h: (JSC::lookupPut):
  • runtime/MathObject.cpp: (JSC::MathObject::MathObject):
  • runtime/NativeErrorConstructor.cpp: (JSC::NativeErrorConstructor::NativeErrorConstructor): (JSC::NativeErrorConstructor::construct):
  • runtime/NativeErrorPrototype.cpp: (JSC::NativeErrorPrototype::NativeErrorPrototype):
  • runtime/NumberConstructor.cpp: (JSC::NumberConstructor::NumberConstructor):
  • runtime/ObjectConstructor.cpp: (JSC::ObjectConstructor::ObjectConstructor):
  • runtime/PropertyMapHashTable.h: (JSC::PropertyMapEntry::PropertyMapEntry):
  • runtime/PrototypeFunction.cpp: (JSC::PrototypeFunction::PrototypeFunction):
  • runtime/PutPropertySlot.h: (JSC::PutPropertySlot::): (JSC::PutPropertySlot::PutPropertySlot): (JSC::PutPropertySlot::setNewProperty): (JSC::PutPropertySlot::setDespecifyFunctionProperty): (JSC::PutPropertySlot::isCacheable): (JSC::PutPropertySlot::cachedOffset):
  • runtime/RegExpConstructor.cpp: (JSC::RegExpConstructor::RegExpConstructor):
  • runtime/StringConstructor.cpp: (JSC::StringConstructor::StringConstructor):
  • runtime/StringPrototype.cpp: (JSC::StringPrototype::StringPrototype):
  • runtime/Structure.cpp: (JSC::Structure::Structure): (JSC::Structure::~Structure): (JSC::Structure::materializePropertyMap): (JSC::Structure::addPropertyTransitionToExistingStructure): (JSC::Structure::addPropertyTransition): (JSC::Structure::changeFunctionTransition): (JSC::Structure::addPropertyWithoutTransition): (JSC::Structure::get): (JSC::Structure::despecifyFunction): (JSC::Structure::put): (JSC::Structure::remove):
  • runtime/Structure.h: (JSC::Structure::get): (JSC::Structure::specificFunction):
  • runtime/StructureTransitionTable.h: (JSC::StructureTransitionTableHashTraits::emptyValue):
  • wtf/Platform.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/Structure.cpp

    r43122 r44076  
    124124    : m_typeInfo(typeInfo)
    125125    , m_prototype(prototype)
     126    , m_specificValueInPrevious(0)
    126127    , m_propertyTable(0)
    127128    , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)
     
    159160            m_previous->m_transitions.singleTransition = 0;
    160161        } else {
    161             ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious.get(), m_attributesInPrevious)));
    162             m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious));
     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)));
    163164        }
    164165    }
     
    280281        structure = structures[i];
    281282        structure->m_nameInPrevious->ref();
    282         PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, ++m_propertyTable->lastIndexUsed);
     283        PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed);
    283284        insertIntoPropertyMapHashTable(entry);
    284285    }
     
    327328}
    328329
    329 PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, size_t& offset)
     330PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
    330331{
    331332    ASSERT(!structure->m_isDictionary);
     
    334335    if (structure->m_usingSingleTransitionSlot) {
    335336        Structure* existingTransition = structure->m_transitions.singleTransition;
    336         if (existingTransition && existingTransition->m_nameInPrevious.get() == propertyName.ustring().rep() && existingTransition->m_attributesInPrevious == attributes) {
     337        if (existingTransition && existingTransition->m_nameInPrevious.get() == propertyName.ustring().rep()
     338            && existingTransition->m_attributesInPrevious == attributes
     339            && existingTransition->m_specificValueInPrevious == specificValue) {
     340
    337341            ASSERT(structure->m_transitions.singleTransition->m_offset != noOffset);
    338342            offset = structure->m_transitions.singleTransition->m_offset;
     
    340344        }
    341345    } else {
    342         if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes))) {
     346        if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), make_pair(attributes, specificValue)))) {
    343347            ASSERT(existingTransition->m_offset != noOffset);
    344348            offset = existingTransition->m_offset;
     
    350354}
    351355
    352 PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, size_t& offset)
     356PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
    353357{
    354358    ASSERT(!structure->m_isDictionary);
    355359    ASSERT(structure->typeInfo().type() == ObjectType);
    356     ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset));
     360    ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
    357361
    358362    if (structure->transitionCount() > s_maxTransitionLength) {
    359363        RefPtr<Structure> transition = toDictionaryTransition(structure);
    360         offset = transition->put(propertyName, attributes);
     364        offset = transition->put(propertyName, attributes, specificValue);
    361365        if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
    362366            transition->growPropertyStorageCapacity();
     
    365369
    366370    RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
     371
    367372    transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
    368373    transition->m_previous = structure;
    369374    transition->m_nameInPrevious = propertyName.ustring().rep();
    370375    transition->m_attributesInPrevious = attributes;
     376    transition->m_specificValueInPrevious = specificValue;
    371377    transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
    372378    transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
     
    386392    }
    387393
    388     offset = transition->put(propertyName, attributes);
     394    offset = transition->put(propertyName, attributes, specificValue);
    389395    if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
    390396        transition->growPropertyStorageCapacity();
     
    402408        StructureTransitionTable* transitionTable = new StructureTransitionTable;
    403409        structure->m_transitions.table = transitionTable;
    404         transitionTable->add(make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition);
    405     }
    406     structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get());
     410        transitionTable->add(make_pair(existingTransition->m_nameInPrevious.get(), make_pair(existingTransition->m_attributesInPrevious, existingTransition->m_specificValueInPrevious)), existingTransition);
     411    }
     412    structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), make_pair(attributes, specificValue)), transition.get());
    407413    return transition.release();
    408414}
     
    431437    transition->m_propertyTable = structure->copyPropertyTable();
    432438    transition->m_isPinnedPropertyTable = true;
     439
     440    return transition.release();
     441}
     442
     443PassRefPtr<Structure> Structure::changeFunctionTransition(Structure* structure, const Identifier& replaceFunction)
     444{
     445    RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo());
     446
     447    transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
     448    transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
     449
     450    // Don't set m_offset, as one can not transition to this.
     451
     452    structure->materializePropertyMapIfNecessary();
     453    transition->m_propertyTable = structure->copyPropertyTable();
     454    transition->m_isPinnedPropertyTable = true;
     455
     456    bool removed = transition->despecifyFunction(replaceFunction);
     457    ASSERT_UNUSED(removed, removed);
    433458
    434459    return transition.release();
     
    482507}
    483508
    484 size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes)
     509size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
    485510{
    486511    ASSERT(!m_transitions.singleTransition);
     
    489514
    490515    m_isPinnedPropertyTable = true;
    491     size_t offset = put(propertyName, attributes);
     516    size_t offset = put(propertyName, attributes, specificValue);
    492517    if (propertyStorageSize() > propertyStorageCapacity())
    493518        growPropertyStorageCapacity();
     
    565590}
    566591
    567 size_t Structure::get(const Identifier& propertyName, unsigned& attributes)
    568 {
    569     ASSERT(!propertyName.isNull());
    570 
     592size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue)
     593{
    571594    materializePropertyMapIfNecessary();
    572595    if (!m_propertyTable)
    573596        return notFound;
    574597
    575     UString::Rep* rep = propertyName._ustring.rep();
    576 
    577598    unsigned i = rep->computedHash();
    578599
     
    587608    if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
    588609        attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
     610        specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue;
    589611        return m_propertyTable->entries()[entryIndex - 1].offset;
    590612    }
     
    609631        if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
    610632            attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
     633            specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue;
    611634            return m_propertyTable->entries()[entryIndex - 1].offset;
    612635        }
     
    614637}
    615638
    616 size_t Structure::put(const Identifier& propertyName, unsigned attributes)
     639bool Structure::despecifyFunction(const Identifier& propertyName)
     640{
     641    ASSERT(!propertyName.isNull());
     642
     643    materializePropertyMapIfNecessary();
     644    if (!m_propertyTable)
     645        return false;
     646
     647    UString::Rep* rep = propertyName._ustring.rep();
     648
     649    unsigned i = rep->computedHash();
     650
     651#if DUMP_PROPERTYMAP_STATS
     652    ++numProbes;
     653#endif
     654
     655    unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
     656    if (entryIndex == emptyEntryIndex)
     657        return false;
     658
     659    if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
     660        ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
     661        m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
     662        return true;
     663    }
     664
     665#if DUMP_PROPERTYMAP_STATS
     666    ++numCollisions;
     667#endif
     668
     669    unsigned k = 1 | doubleHash(rep->computedHash());
     670
     671    while (1) {
     672        i += k;
     673
     674#if DUMP_PROPERTYMAP_STATS
     675        ++numRehashes;
     676#endif
     677
     678        entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
     679        if (entryIndex == emptyEntryIndex)
     680            return false;
     681
     682        if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
     683            ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
     684            m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
     685            return true;
     686        }
     687    }
     688}
     689
     690size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
    617691{
    618692    ASSERT(!propertyName.isNull());
     
    684758    m_propertyTable->entries()[entryIndex - 1].key = rep;
    685759    m_propertyTable->entries()[entryIndex - 1].attributes = attributes;
     760    m_propertyTable->entries()[entryIndex - 1].specificValue = specificValue;
    686761    m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed;
    687762
     
    756831    m_propertyTable->entries()[entryIndex - 1].key = 0;
    757832    m_propertyTable->entries()[entryIndex - 1].attributes = 0;
     833    m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
    758834    m_propertyTable->entries()[entryIndex - 1].offset = 0;
    759835
Note: See TracChangeset for help on using the changeset viewer.